I know I can't mutably borrow more than once at a time. I'm trying to structure the scopes in my program such that each borrow ends before the next begins. However, using an explicit return
seems to throw off the scoping rules so that I can't do the borrows the way I want.
Here's an example of what I mean. Ignore the trait definition, the content is in the body of the function.
trait BTreeMapExt<K, V> where K: Ord, V: Default {
fn get_mut_default(&mut self, key: K) -> &mut V;
}
impl<K, V> BTreeMapExt<K, V> for BTreeMap<K, V> where K: Ord, V: Default {
fn get_mut_default(&mut self, key: K) -> &mut V {
{
let x = self.get_mut(&key);
match x {
Some(value) => return value, // Error [E0499]: cannot borrow `*self` as mutable more than once at a time
None => (),
};
}
{
let y = self.insert(key, V::default());
}
unimplemented!();
}
}
If you replace the return value
with any other expression (e.g. ()
), then everything works fine. The nested scopes are sufficient to keep the mutable borrows from interfering.
There must clearly be something about the borrow checker I'm not understanding here. Perhaps the use of return
causes the borrow scope to run until the end of the function? Otherwise I can't make sense of this.
P.S. In case you're wondering what I'm trying to do here: I'm trying to define an operator that works like operator[]
in C++'s std::map
class, i.e. create the element with a default value if it doesn't exist and return a reference to it either way. I'm not sure how to even define this if the pattern above doesn't work. The code I would have wanted to write is below.
trait BTreeMapExt<K, V> where K: Ord, V: Default {
fn get_mut_default(&mut self, key: K) -> &mut V;
}
impl<K, V> BTreeMapExt<K, V> for BTreeMap<K, V> where K: Ord, V: Default {
fn get_mut_default(&mut self, key: K) -> &mut V {
match self.get_mut(&key) {
Some(value) => return value,
_ => () // Fall through: the key does not exist
}
match self.insert(key, V::default()) {
Some(_) => unreachable!(), // Can't happen, we just checked the key
_ => (), // Fall through: the insertion succeeded
}
match self.get_mut(&key) {
Some(value) => value,
_ => unreachable!(), // Can't happen, we just inserted the key
}
}
}