I've read about the Entry API for hash maps, but I'm a bit stuck on how to use it. Consider the following:
// does not compile...
use std::collections::HashMap;
struct Item {
id: u32,
value: String,
}
struct Obj {
map: HashMap<String, Item>,
}
impl Obj {
pub fn check(&mut self, key: &str, check_id: u32) {
// retrieve current item for key (if it exists)
let item = self.map.get(key);
// do some complex matching on the item to determine
// what to do next
match item {
Some(&Item { id, .. }) if id == check_id => {
// item exists, and has same id, nothing more to do
println!("found checked id");
},
_ => {
// else, we need to mutate the map, e.g. like this
self.map.insert(String::from(key),
Item { id: check_id, value: String::new() });
},
}
}
}
fn main() {
let mut obj = Obj { map: HashMap::new() };
// fill like...
//obj.map.insert(String::from("a"), Item { id: 0, value: String::from("xxx") });
obj.check("a", 0);
}
Obviously this does not compile since the item retrieved from map.get()
keeps an immutable borrow of the map
, so that there can't be an immutable borrow from insert
.
Currently I see five ways to get around this:
- do the retrieval and matching in a separate scope/function, which returns a flag indicating if the
insert
or other mutation has to be done - make
Item
cloneable and doself.map.get(key).map(|v| v.clone())
(btw, is there a better way to write this?) -- seems fine right now, but probably not anymore if the Item contains lots of data - remove the
Item
withremove
instead ofget
, then reinsert it if necessary
This is what the entry API was written for, right? How to do it?