Resolved: In Rust, can I return FnMut with a captured mutable reference, perhaps by specifying a generic lifetime?

Question:

Is it possible to specify a generic lifetime on FnMut 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
}
Playground

If you have better answer, please add a comment about this, thank you!