Hi, I'm a complete beginner at Rust, coming from a Java / Go background. The code below helps memoize a recursive function func
, and compiles / runs fine.
pub struct FnCache<'a, I, O> {
cache: HashMap<I, O>,
func: &'a dyn Fn(&I, &mut Self) -> O,
}
impl<'a, I: Eq + Hash, O: Clone> FnCache<'a, I, O> {
pub fn get(&mut self, input: I) -> O {
match self.cache.get(&input) {
Some(val) => val.clone(),
None => {
let result = (self.func)(&input, self);
self.cache.entry(input).or_insert(result).clone()
}
}
}
}
I want to refactor it as below, so that I can return the built cache from another function. The above code won't work as it requires a reference to the closure created in the function, which goes away after the function goes out of scope. Makes sense to me.
pub struct FnCache<I, O> {
cache: HashMap<I, O>,
func: Box<dyn Fn(&I, &mut Self) -> O>,
}
impl<I: Eq + Hash, O: Clone> FnCache<I, O> {
pub fn get(&mut self, input: I) -> O {
match self.cache.get(&input) {
Some(val) => val.clone(),
None => {
let result = (self.func)(&input, self); // cannot borrow `*self` as mutable because it is also borrowed as immutable
self.cache.entry(input).or_insert(result).clone()
}
}
}
}
Compile fails with error
let result = (self.func)(&input, self);
| -----------^^^^^^^^^^^^^^
| |
| mutable borrow occurs here
| immutable borrow occurs here
| immutable borrow later used by call
Logically speaking, the check can be ignored, since self.func
cannot be modified. But I guess the compiler has no way of knowing that.
My question is, why does the first example compile, when I'm also immutably borrowing self.func
and passing it a mutable reference to self
? Any fix will also be greatly appreciated.
Thanks for your help!