From 7da9ea0af48ccf9468863408b449d33c415cbde7 Mon Sep 17 00:00:00 2001 From: Val Vanderschaegen Date: Thu, 12 May 2016 18:56:20 -0700 Subject: [PATCH] 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. --- src/doc/book/closures.md | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index d81619b647f..7bfe67f4c8b 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -319,6 +319,53 @@ assert_eq!(3, answer); Now we take a trait object, a `&Fn`. And we have to make a reference to our closure when we pass it to `call_with_one`, so we use `&||`. +A quick note about closures that use explicit lifetimes. Sometimes you might have a closure +that takes a reference like so: + +``` +fn call_with_ref(some_closure:F) -> i32 + where F: Fn(&i32) -> i32 { + + let mut value = 0; + some_closure(&value) +} +``` + +Normally you can specify the lifetime of the parameter to our closure. We +could annotate it on the function declaration: + +``` +fn call_with_ref<'a, F>(some_closure:F) -> i32 + where F: Fn(&'a 32) -> i32 { +``` + +However this presents a problem with in our case. When you specify the explict +lifetime on a function it binds that lifetime to the *entire* scope of the function +instead of just the invocation scope of our closure. This means that the borrow checker +will see a mutable reference in the same lifetime as our immutable reference and fail +to compile. + +In order to say that we only need the lifetime to be valid for the invocation scope +of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: + +``` +fn call_with_ref(some_closure:F) -> i32 + where F: for<'a> Fn(&'a 32) -> i32 { +``` + +This lets the rust compiler find the minimum lifetime to invoke our closure and +satisfy the borrow checker's rules. Our function then compiles and excutes as we +expect. + +``` +fn call_with_ref(some_closure:F) -> i32 + where F: for<'a> Fn(&'a i32) -> i32 { + + let mut value = 0; + some_closure(&value) +} +``` + # Function pointers and closures A function pointer is kind of like a closure that has no environment. As such,