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