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
}
Playground