Note: actually duplicated with Recursive iteration while caching into HashMap, you can lookup various solutions in this thread.
Note2: Maybe simply store Rc<>
or Arc<>
in the HashMap
is a good alternative to use polonius.
Hi,
I'm using a HashMap
to cache some very time-consuming calculation result, avoiding repeated calculation for the same inputs. So I write code like following, playground:
use std::collections::HashMap;
#[derive(Default)]
struct Cache {
cache: HashMap<u8, u64>
}
impl Cache {
fn get_or_calculate(&mut self, key: u8) -> &u64 {
if let Some(value) = self.cache.get(&key) {
return value;
}
let mut computation_result = 0;
// simulate some very time consuming computations...
// note that there would be a large block of code actually
for _ in 0..100000000 {
computation_result += 1;
}
self.cache.entry(key).or_insert(computation_result)
}
}
fn main() {
let cache = Cache::default();
println!("{:?}", *cache.get_or_calculate(1));
}
But Rust compiler rejects to compile this code:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `self.cache` as mutable because it is also borrowed as immutable
--> src/main.rs:21:9
|
9 | fn get_or_calculate(&mut self, key: u8) -> &u64 {
| - let's call the lifetime of this reference `'1`
10 | if let Some(value) = self.cache.get(&key) {
| ---------- immutable borrow occurs here
11 | return value;
| ----- returning this value requires that `self.cache` is borrowed for `'1`
...
21 | self.cache.entry(key).or_insert(computation_result)
| ^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
error[E0596]: cannot borrow `cache` as mutable, as it is not declared as mutable
--> src/main.rs:28:23
|
28 | println!("{:?}", *cache.get_or_calculate(1));
| ^^^^^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
26 | let mut cache = Cache::default();
| +++
Some errors have detailed explanations: E0502, E0596.
For more information about an error, try `rustc --explain E0502`.
error: could not compile `playground` (bin "playground") due to 2 previous errors
From my understanding to Rust lifetime, the reference value
is early-returned in the code above, so the lifetime of the implicitly created immutable reference to self.cache
created by self.cache.get
invocation should end at the same time. However, it seems that Rust compiler assumes this reference live until the whole method end, and prevent me from creating a mutable reference to self.cache
. What's wrong with my understanding to Rust lifetime mechanism?
Besides, due to actual computation logic is a large block of code and won't get re-used in other parts of code, I don't want to encapsulate them with a new method or function, and I don't want this part of code to have addtional idention. Otherwise I can simply write self.cache.entry(key).or_insert_with(...)
. Is there any possible ways to rewrite get_or_calculate
method as what I want to?