65. Precise Capturing — Stop impl Trait From Borrowing Too Much
Ever had the compiler refuse to let you use a value after calling a function — even though the return type shouldn’t borrow it? use<> bounds give you precise control over what impl Trait actually captures.
The overcapturing problem
In Rust 2024, impl Trait in return position captures all in-scope generic parameters by default — including lifetimes you never intended to hold onto.
Here’s where it bites:
| |
Without the use<> bound, the returned impl Display would capture the &str lifetime — even though format! produces an owned String that doesn’t borrow name at all. That means the caller can’t drop or reuse name while the return value is alive, for no good reason.
Enter use<> bounds
Stabilized in Rust 1.82, the use<> syntax lets you explicitly declare which generic parameters the opaque type is allowed to capture:
| |
use<> means “capture nothing” — the return type is fully owned and independent of any input lifetimes.
Selective capturing
You can also pick exactly which lifetimes to capture. Consider a function that takes two references but only needs to hold onto one:
| |
use<'a> says “this return type borrows from 'a but is independent of 'b.” Without it, the compiler assumes the opaque type captures both lifetimes, preventing you from reusing config.
When you need this
The use<> bound shines when you’re returning iterators, closures, or other impl Trait types from functions that take references they don’t actually need to hold:
| |
A small annotation that unlocks flexibility the compiler couldn’t infer on its own. If you’ve upgraded to Rust 2024 and hit mysterious “borrowed value does not live long enough” errors on impl Trait returns, use<> is likely the fix.