Matthias
Matthias

Reputation: 1215

How to add lifetime argument to closure not returning a reference

Assume you have a function returning a closure which works on a reference. Sure, the object behind the reference must life at least as long as the closure is called.

Here a very simple example, which demonstrates the problem.

fn get_cloned<'a>(obj: &'a MyStruct) -> impl Fn() -> MyStruct {
    || {obj.clone()}
}

The compiler states that the returned closure has lifetime static:

cannot infer an appropriate lifetime
...but this borrow...rustc
main.rs(60, 56): this return type evaluates to the 'static lifetime...
main.rs(61, 5): ...but this borrow...

How can I tell the compiler that I only use the result of the function (the closure) as long as the reference is valid?

Thanks!

[Edit]

Do you need a dummy struct which holds the reference as well as the closure?

struct Dummy<'a>{
  reference: &'a MyStruct,
  closure: Fn() -> MyStruct
}

?

Assume that cloning is very costly and the closure might never be called. -> lazy evaluation is a must.

Upvotes: 0

Views: 923

Answers (1)

mcarton
mcarton

Reputation: 30111

The compiler tells you what to do:

error: cannot infer an appropriate lifetime
 --> src/lib.rs:2:9
  |
1 | fn get_cloned<'a>(obj: &'a MyStruct) -> impl Fn() -> MyStruct {
  |                                         --------------------- this return type evaluates to the `'static` lifetime...
2 |         || {obj.clone()}
  |         ^^^^^^^^^^^^^^^^ ...but this borrow...
  |
note: ...can't outlive the lifetime 'a as defined on the function body at 1:15
 --> src/lib.rs:1:15
  |
1 | fn get_cloned<'a>(obj: &'a MyStruct) -> impl Fn() -> MyStruct {
  |               ^^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime 'a as defined on the function body at 1:15
  |
1 | fn get_cloned<'a>(obj: &'a MyStruct) -> impl Fn() -> MyStruct + 'a {
  |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^

You need to add + 'a on the return type. The compiler will then tell you you're missing move, but after fixing that, your code works:

fn get_cloned<'a>(obj: &'a MyStruct) -> impl Fn() -> MyStruct + 'a {
    || {obj.clone()}
}

Upvotes: 1

Related Questions