jm4ier
jm4ier

Reputation: 237

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

Upvotes: 5

Views: 1327

Answers (2)

Sven Marnach
Sven Marnach

Reputation: 601351

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);

Upvotes: 10

jm4ier
jm4ier

Reputation: 237

I've just found out a way to solve this issue, but It'd be great if there is an easier solution:

fn infer_lifetime<'a, T: 'a, F: Fn(&'a T) -> &'a T>(f: F) -> F {
    f
}

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

Upvotes: 1

Related Questions