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