Managing lifetimes in closure

Hi !

I'm trying to make working my lifetimes without success. There is an sample code :

use std::sync::{Arc, RwLock, RwLockWriteGuard};

struct MyStruct;

struct State(Arc<RwLock<Vec<MyStruct>>>);

struct Processor {
    state: Arc<State>,
}

impl Processor {
    fn process<T, F>(&self, get: F)
    where
        F: for<'a> Fn(&'a mut RwLockWriteGuard<'a, Vec<MyStruct>>, usize) -> &'a mut T,
    {
        let mut structs = self.state.0.write().unwrap();
        let _ = get(&mut structs, 42);
    }
}

fn main() {
    let objects = vec![];
    let state = Arc::new(State(Arc::new(RwLock::new(objects))));
    let processor = Processor { state };
    processor.process(|s, i| &mut s[i]);
}
error[E0597]: `structs` does not live long enough
  --> src/main.rs:17:21
   |
16 |         let mut structs = self.state.0.write().unwrap();
   |             ----------- binding `structs` declared here
17 |         let _ = get(&mut structs, 42);
   |                     ^^^^^^^^^^^^ borrowed value does not live long enough
18 |     }
   |     -
   |     |
   |     `structs` dropped here while still borrowed
   |     borrow might be used here, when `structs` is dropped and runs the `Drop` code for type `std::sync::RwLockWriteGuard`

I reduced my real code in this example. I have a function process which take a closure get which must be able to take a mutable reference from a RwLock inside it.

So, the get closure must return a reference which live same lifetime than reference inside RwLockWriteGuard.

I tried a lot of combination of lifetime without success. Lifetimes are a difficult part for me ... :smiley:

Any help ?

I found a working solution by random tries ...

impl Processor {
    fn process<T, F>(&self, get: F)
    where
        F: for<'a> Fn(&'a mut Vec<MyStruct>, usize) -> &'a mut T,
    {
        let mut structs = self.state.0.write().unwrap();
        let x = get(&mut structs, 42);
    }
}

I take an explanation if someone have it !

the problem is the &'a mut RwLockWriteGuard<'a, ...> type, which is a common source for lifetime related errors, because mut references are invariant. see:

try something like this:

    fn process<T, F>(&self, get: F)
    where
        F: for<'a, 'b> Fn(&'a mut RwLockWriteGuard<'b, Vec<MyStruct>>, usize) -> &'a mut T
    {
        //...
    }

or this:

    fn process<T, F>(&self, get: F)
    where
        F: for<'a> Fn(&'a mut RwLockWriteGuard<'_, Vec<MyStruct>>, usize) -> &'a mut T
    {
        //...
    }

The lifetime parameter of the RwLockWriteGuard is the lifetime of its borrow of the RwLock. So the most specific, informative lifetime annotation you could use on your original code is:

impl Processor {
    fn process<'s, T, F>(&'s self, get: F)
    where
        F: for<'a> Fn(&'a mut RwLockWriteGuard<'s, Vec<MyStruct>>, usize) -> &'a mut T,
    {

However, for most purposes, your for<'a> Fn(&'a mut Vec<MyStruct>, usize) -> &'a mut T is a better choice, because it is simpler to understand, and the function doesn't need to know about the lock guard at all.

Thank you for your explanations ! That's a complicated side for me. I will study that.

Incidentally, if it's possible to call the closure exclusively -- which is usually the case for closures you take as arguments and drop at the end of the method -- it's kinder to the caller if you take a FnMut instead of a Fn.

And if you're only ever going to call it once, it's even kinder to take a FnOnce.