I have a structure that contains a value and I want to obtain a function that operates on this value:
struct Returner {
val: i32,
}
impl<'a> Returner {
fn get(&'a self) -> Box<Fn(i32) -> i32> {
Box::new(|x| x + self.val)
}
}
This fails compilation:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:7:18
|
7 | Box::new(|x| x + self.val)
| ^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 5:1...
--> src/main.rs:5:1
|
5 | impl<'a> Returner {
| ^^^^^^^^^^^^^^^^^
= note: ...so that the types are compatible:
expected &&Returner
found &&'a Returner
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<std::ops::Fn(i32) -> i32 + 'static>
found std::boxed::Box<std::ops::Fn(i32) -> i32>
This is because the closure borrows self
, which is fine by me, because I don't intend to use the obtained function after the struct is destroyed. From what I've gathered so far, there's two ways to make it possible:
Use the
move
keyword. I don't want to use it because it will take ownership on the object, and want I to use it after it has returned this function.Explicitly specify the lifetime of the closure to tell the compiler that it has the same lifetime as the struct it was called from.
I think that 2 is the correct way in my situation, but I've not been able to find out how to specify the closure's lifetime. Is there a direct way to do it or I've got it all wrong and it contradicts Rust lifetime logic?
As said in an existing answer:
self
to the lifetime of the returned value.self
into the closure.Since Rust 1.26, you no longer need to return a boxed closure if you are only returning a single type. Instead, you can use
impl Trait
:See also:
In general, you can specify the lifetime of a boxed trait object by writing
Box<Trait + 'a>
and analogously for trait objects behind other kinds of pointers (if it's omitted, it defaults to'static
at least in the case ofBox
). So in this specific case you want the return typeBox<(Fn(i32) -> i32) + 'a>
.However, when you do that you will see another error about
self
not living long enough. The reason is that (withoutmove
) the closure will capture a reference to the local variableself
. The solution is to usemove
. This does not move theReturner
object, it movesself
which is a reference to theReturner
object.In summary: