Skip to content

Commit 7da9ea0

Browse files
committed
Add a note about Higher-Ranked Trait Bounds in docs on Closures.
When using closures that take references with explicit lifetimes sometimes it's required to use where F: for<..> ... syntax to express the right lifetimes. This adds a quick note to the docs so other users can discover it as well.
1 parent e88defe commit 7da9ea0

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

src/doc/book/closures.md

+47
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+
```
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+
```
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)