Skip to content

Commit e4f33d5

Browse files
committed
Rollup merge of rust-lang#33611 - vvanders:master, r=steveklabnik
Add a note about Higher-Ranked Trait Bounds in docs on Closures. I hit a snag with lifetimes a few days ago and it wasn't until @birkenfeld pointed out Higher-Ranked Trait Bounds that I was able to solve the issue involving lifetimes on closure traits. This adds a small section in the book so that other users can find it. r? @steveklabnik
2 parents c9ca735 + 64feba0 commit e4f33d5

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

src/doc/book/closures.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,53 @@ assert_eq!(3, answer);
319319
Now we take a trait object, a `&Fn`. And we have to make a reference
320320
to our closure when we pass it to `call_with_one`, so we use `&||`.
321321

322+
A quick note about closures that use explicit lifetimes. Sometimes you might have a closure
323+
that takes a reference like so:
324+
325+
```
326+
fn call_with_ref<F>(some_closure:F) -> i32
327+
where F: Fn(&i32) -> i32 {
328+
329+
let mut value = 0;
330+
some_closure(&value)
331+
}
332+
```
333+
334+
Normally you can specify the lifetime of the parameter to our closure. We
335+
could annotate it on the function declaration:
336+
337+
```ignore
338+
fn call_with_ref<'a, F>(some_closure:F) -> i32
339+
where F: Fn(&'a 32) -> i32 {
340+
```
341+
342+
However this presents a problem with in our case. When you specify the explict
343+
lifetime on a function it binds that lifetime to the *entire* scope of the function
344+
instead of just the invocation scope of our closure. This means that the borrow checker
345+
will see a mutable reference in the same lifetime as our immutable reference and fail
346+
to compile.
347+
348+
In order to say that we only need the lifetime to be valid for the invocation scope
349+
of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax:
350+
351+
```ignore
352+
fn call_with_ref<F>(some_closure:F) -> i32
353+
where F: for<'a> Fn(&'a 32) -> i32 {
354+
```
355+
356+
This lets the Rust compiler find the minimum lifetime to invoke our closure and
357+
satisfy the borrow checker's rules. Our function then compiles and excutes as we
358+
expect.
359+
360+
```
361+
fn call_with_ref<F>(some_closure:F) -> i32
362+
where F: for<'a> Fn(&'a i32) -> i32 {
363+
364+
let mut value = 0;
365+
some_closure(&value)
366+
}
367+
```
368+
322369
# Function pointers and closures
323370

324371
A function pointer is kind of like a closure that has no environment. As such,

0 commit comments

Comments
 (0)