In Rust I am trying to update a cache and then return the result.
fn cached_res(&mut self) -> &Vec<u64> {
if self.last_update.elapsed() >= REFRESH_RATE {
self.a = do_something(...);
}
return &self.a;
}
fn use_cached_res(&mut self) {
let b = self.cached_res();
b.iter().map(|x| x + 1).collect()
}
And the compilation fails due to
173 | let b = cached_res(self);
| ---- mutable borrow occurs here
...
179 | .map(|f| self.do_something(&f))
| --- ^^^ ---- second borrow occurs due to use of `*self` in closure
| | |
| | immutable borrow occurs here
| mutable borrow later used by call
I think I understand why it fails and a possible workaround could be to have a method that only updates the cache and another that returns the result so in that way the mutable borrow is dropped and b is not borrowed as mutable.
fn refresh(&mut self) {
if self.last_update.elapsed() >= REFRESH_RATE {
self.a = do_something(...);
}
}
fn res(&self) -> &Vec<u64> {
&self.a
}
fn use_cached_res(&mut self) {
self.refresh();
let b = self.res();
b.iter().map(|x| x + 1).collect()
}
However, I would like to have these constraints defined in cached_res so that downstream users don't have to use such methods in the right sequence. IIUC what I want is that cached_res returns an immutable borrow of self after having modified self.
Please let me know if there is additional information or clarifications that I can provide.
One way to solve it is with interior mutability using
RefCell:This has some extra overhead to keep track of borrows at runtime, but will give you the most flexibility and would even allow you to return
impl DerefMutif you like. You can easily translate this toRwLock(borrow_mut->writeandborrow->read) orMutex(lock) if you need this struct to beSync.Another way is to invert the control flow by taking a closure:
This puts constraints on how you can use
cached_resbut doesn't require changing your struct or introducing overhead.