Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I not return a reference from a closure?

fn main() {
    let _ref_in_ref_out = |var: &i64| var;
}

This does not compile:

error: lifetime may not live long enough
 --> src/main.rs:2:39
  |
2 |     let _ref_in_ref_out = |var: &i64| var;
  |                                 -   - ^^^ returning this value requires that `'1` must outlive `'2`
  |                                 |   |
  |                                 |   return type of closure is &'2 i64
  |                                 let's call the lifetime of this reference `'1`

Apparently the compiler infers two different lifetimes (for the argument and the return type), instead of it being the same.

Is it possible to write a closure so that the input lifetime is the same as the output lifetime?

Something like

fn ref_in_ref_out<'a> (var: &'a i64) -> &'a i64  { var }

but as a closure

like image 866
jm4ier Avatar asked Sep 11 '20 09:09

jm4ier


1 Answers

Lifetime elisions rules do not apply to closures, neither can you explicitly specify lifetimes for closures. There are several ways to make this code work, though.

The easiest solution is to simply omit the type annotations and let the compiler infer everything:

let ref_in_ref_out = |var| var;
let i: i64 = 42;
ref_in_ref_out(&i);

Alternatively, it's actually fine to specify the return type. This compiles:

let _ref_in_ref_out = |var| -> &i64 { var };

Yet another option for the case that your closure does not close over any local variables is to convert it to a function pointer, since lifetime elision rules apply to function pointers:

let ref_in_ref_out: fn(&i64) -> &i64 = |var| var;

And finally the most general solution is to use a helper function to apply a function trait bound to your closure:

fn constrain_closure<F: Fn(&i64) -> &i64>(f: F) -> F {
    f
}

let _ref_in_ref_out = constrain_closure(|var| var);
like image 119
Sven Marnach Avatar answered Sep 28 '22 20:09

Sven Marnach