Question:
Is it possible to specify a generic lifetime onFnMut
in Rust for a function like this?fn f1<'a, FRet:'a + FnMut() -> ()>(v: &'a mut i32) -> FRet {
let mut fret = || {
let i = v;
println!("inside");
// lots of complicated logic on captured var
*i = 5;
};
return fret;
}
Right now I’m getting an error, that return is incompatible with FRet
.Answer:
Your code has several issues. One is that you cannot make the function that returns a closure have a generic return type.f1
being generic over FRet
means that the caller gets to choose the FRet
, and that obviously can’t work when you’re returning a closure you implement, and not something the caller to specify. This is why the compiler complains that FRet
is incompatible with what you’re actually returning.The way to return a closure is by either boxing it or using the
impl Trait
return type that declares an unnamed type returned by the function:fn f1(v: &mut i32) -> impl FnMut() {
let fret = || {
let i = v;
println!("inside");
// lots of complicated logic on captured var
*i = 5;
};
fret
}
The above still doesn’t compile with the compiler complaining that the closure is FnOnce
rather than FnMut
. This is because &mut i32
is not Copy
, so let i = v
actually moves the reference out of v
which makes the closure callable only once. That can be fixed with a reborrow, i.e. changing let i = v
to let i = &mut *v
.After that the compiler will complain that the lifetime of reference is not captured by the closure, and that you can fix that by adding
+ '_
. (This is equivalent to declaring a lifetime 'a
and declaring v: &'a mut i32
and impl FnMut() + 'a
.) With this change the code compiles:fn f1(v: &mut i32) -> impl FnMut() + '_ {
let fret = || {
let i = &mut *v;
println!("inside");
// lots of complicated logic on captured var
*i = 5;
};
fret
}
PlaygroundIf you have better answer, please add a comment about this, thank you!
Leave a Review