Closure parameter and return value lifetimes

Would you have any idea about below issue with closure?

fn f1(w: &str) -> &str {
    w
}

fn main() {
    let hello = "hello";
    
    let f2 = |w: &str| -> &str {
        w
    };
    
    assert_eq!(f2(hello), hello);
}

failed with:

   Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
 --> src/main.rs:9:9
  |
8 |     let f2 = |w: &str|  {
  |                  -   - return type of closure is &'2 str
  |                  |
  |                  let's call the lifetime of this reference `'1`
9 |         w
  |         ^ returning this value requires that `'1` must outlive `'2`

error: could not compile `playground` (bin "playground") due to 1 previous error

while it works when it is defined as function: Rust Playground

fn f1(w: &str) -> &str {
    w
}

fn main() {
    let hello = "hello";
    assert_eq!(f1(hello), hello);
}

I was just reading 3216-closure-lifetime-binder - The Rust RFC Book which is the answer to your question.

In fact, on nightly, you can enable the feature, and it will compile:

3 Likes

@parasyte's answer explains the issue.

Also note that you can sometimes get better results when you do not annotate the closure params and return value. IME the compiler is better at inferring the types of closures. So this works on stable:

            let f2 = |w| w;
2 Likes

The stable general solution to this problem is to pass the closure to a function whose signature constrains the signature of the closure:

fn same_lt_in_and_out<T: ?Sized, F>(f: F) -> F
where
    F: for<'a> Fn(&'a T) -> &'a T,
{
    f
}

let f2 = same_lt_in_and_out(|w: &str| -> &str { w });

The Rust compiler can be understood as essentially having a special rule that says "when a closure is passed to a function with a Fn* bound, use that bound as the closure's signature”. This is why this problem doesn’t come up in common uses of closures like Iterator::map(): most of the time, the closures do get passed directly to functions for use as callbacks of some sort.

5 Likes

thanks all for advice and insight :slight_smile: