I am trying to implement lazy-construction / memoized evaluation / caching idioms in Rust.
How it works, there is an external type that contains a bunch of data and an access method. The accessor method must either return the cached calculation (if any), or calculate it and save the return value on the map for later use. The value being cached does not need to reference an external value, so there is no circular reference problem; but he needs access to external meaning data in order to build himself.
Here's a complete example that fails Rust's borrowing test:
use std::collections::HashMap;
pub struct ContainedThing {
count: usize,
}
impl ContainedThing {
fn create(thing: &Thing) -> ContainedThing {
// create uses an arbitrary number of attributes from Thing
// it doesn't keep any references after returning though
let count = thing.map.len();
ContainedThing { count: count }
}
}
struct Thing {
map: HashMap<i32,ContainedThing>,
}
impl Thing {
pub fn get(&mut self, key: i32) -> &ContainedThing {
self.map.entry(key).or_insert_with(|| ContainedThing::create(&self))
}
}
fn main() {
}
The specific error is this:
test.rs:20:44: 20:46 error: cannot borrow `self` as immutable because `self.map` is also borrowed as mutable [E0502]
test.rs:20 self.map.entry(key).or_insert_with(|| ContainedThing::create(&self))
^~
test.rs:20:9: 20:17 note: mutable borrow occurs here
test.rs:20 self.map.entry(key).or_insert_with(|| ContainedThing::create(&self))
^~~~~~~~
test.rs:21:5: 21:6 note: mutable borrow ends here
test.rs:21 }
^
test.rs:20:71: 20:75 note: borrow occurs due to use of `self` in closure
test.rs:20 self.map.entry(key).or_insert_with(|| ContainedThing::create(&self))
^~~~
, . , get(), API entry(), : match self.
get :
pub fn get(&mut self, key: i32) -> &ContainedThing {
if !self.map.contains_key(&key) {
let thing = ContainedThing::create(&self);
self.map.insert(key, thing);
}
self.map.get(&key).unwrap()
}
( unwrap) , , , .
- - .
entry(), , , . - . , .
unwrap; , .
, ?