Why this rust FnMut closure code has lifetime errors?

I want to make a closure hold &mut Vec, but these simple few lines of code cant compile.

I know this can be solved with RefCell, I just cant figure the error out.

struct Server<'a> {
    data: &'a mut Vec<i32>,
}

fn main() {
    let mut data = vec![1, 2, 3];
    let mut c = || {
         Server{
            data: &mut data,
        }
    };
    let server = c();
}

Rust playground link

The error message is:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:36:19
   |
36 |             data: &mut data,
   |                   ^^^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime '_ as defined on the body at 34:17...
  --> src/main.rs:34:17
   |
34 |     let mut c = || {
   |                 ^^
note: ...so that closure can access `data`
  --> src/main.rs:36:19
   |
36 |             data: &mut data,
   |                   ^^^^^^^^^
note: but, the lifetime must be valid for the call at 39:18...
  --> src/main.rs:39:18
   |
39 |     let server = c();
   |                  ^^^
note: ...so type `Server<'_>` of expression is valid during the expression
  --> src/main.rs:39:18
   |
39 |     let server = c();
   |                  ^^^

error: aborting due to previous error

Update:

I found this post answered the question, but I could not understand some parts of it:

It turns out that, returning &'a mut i32 is not feasible for the shorter-live invocation of call_mut. What we’ve really wanted for the return type of call_mut, was something like:

impl<'a> FnMut<(usize,)> for Closure<'a> {
    extern "rust-call"
    fn<'b> call_mut(&'b mut self, (i,): (usize, )) -> &'b mut i32 {
        self.inner.get_mut(i).unwrap()
    }
}
  1. Why the call_mut fn has to use a 'b lifetime instead of 'a?
  2. I found the code would work if change data: &mut Vec<i32> to data: &Vec<i32>, which makes me more confused that why lifetime is related to mut?

The issue here is that the function cannot be FnMut, but has to be FnOnce: to be FnMut, the captured environment &'a mut Vec<i32> is only &'_ mut borrowed for a lifetime '_ that can be smaller than 'a, thus the resulting Server will not be a Server<'a> but a Server<'_>, and that function signature cannot be described by the current FnMut interface (it is the same issue as the one with iterators vs. streaming iterators, which you can look up).

To be able to return a Server<'a>, you need to take the captured environment (i.e., &'a mut Vec<i32>) by value (self: Self), at which point your closure will only be a FnOnce.

The surprising thing is that Rust itself gets lured into trying to define a FnMut that reborrows for some '_, and thus afterwards fails. So it has to be told that it not make a FnMut, but try to make a FnOnce directly:

struct Server<'a> {
    data: &'a mut Vec<i32>,
}

fn make_closure<'a> (data: &'a mut Vec<i32>)
  -> impl FnOnce() -> Server<'a> // the only place where we can currently tell Rust the kind of closure we are looking for
{
    move || Server { data }
}

fn main() {
    let mut data = vec![1, 2, 3];
    let mut c = make_closure(&mut data);/*|| -> Server {
        Server {
            data: &mut data,
        }
    };*/
    let server = c();
}

For a more detailed version of what is happening under the hood, here is a version with a custom FnOnce trait:

struct Server<'a> {
    data: &'a mut Vec<i32>,
}

trait MyFnOnce {
    type Output;
    
    fn call_once (self: Self)
      -> Self::Output
    ;
}

/// The environment captured by the closure: &mut data
struct Env<'a> /* = */ (
    &'a mut Vec<i32>,
);

impl<'a> MyFnOnce for Env<'a> {
    type Output = Server<'a>;

    // call_mut would lead to `self: &'_ mut Env<'a>`,
    // thus returning `Server<'_>`,
    // but `Self::Output` cannot depend on `'_`
    fn call_once(self: Env<'a>)
      -> Server<'a>
    {
        Server { data: self.0 }
    }
}

fn main ()
{
    let mut data = vec![1, 2, 3];
    let c = Env(&mut data);
    let server = c.call_once();
}
2 Likes

Here is the required interface to be able to call_mut:

struct Server<'a> {
    data: &'a mut Vec<i32>,
}

trait StreamingFnMut<'call_borrow> {
    type Output : 'call_borrow;
    
    fn call_mut (self: &'call_borrow mut Self)
      -> Self::Output
    ;
}

/// The environment captured by the closure: &mut data
struct Env<'a> /* = */ (
    &'a mut Vec<i32>,
);

impl<'call_borrow, 'a> StreamingFnMut<'call_borrow>
    for Env<'a>
where
    'a : 'call_borrow,
{
    type Output = Server<'call_borrow>;

    fn call_mut(self: &'call_borrow mut Env<'a>)
      -> Server<'call_borrow>
    {
        Server {
            data: &mut *self.0 // reborrow
        }
    }
}

fn main ()
{
    let mut data = vec![1, 2, 3];
    let mut c = Env(&mut data);
    let server = c.call_mut();
}
3 Likes

Thanks so much for the detailed reply!

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.