I have the following code that inserts some values into a HashMap and then gets them back out:
use std::collections::HashMap;
fn things() {
let mut map
This error is a limitation of the implementation of the borrow checker before non-lexical lifetimes. With those enabled, the original code will work as-is:
use std::collections::HashMap;
fn things() {
let mut map = HashMap::new();
map.insert(5, "thing");
map.insert(4, "world");
map.insert(1, "hello");
let mut thing = map.remove(&5);
let mut world = map.get_mut(&4);
let mut hello = map.get_mut(&1);
}
fn main() {}
This is because the compiler is smarter and can see that you aren't using world
anymore by the time you get to map.get_mut(&1)
, so it doesn't need to have a valid reference anymore.
You can get equivalent code in previous versions of Rust by adding an explicit scope:
let mut thing = map.remove(&5);
{
let mut world = map.get_mut(&4);
}
let mut hello = map.get_mut(&1);
Why does
HashMap::get_mut()
take ownership of the map
It absolutely does not do that. Ownership is a precise term in Rust code. Note that the error message specifically says
previous borrow of
map
occurs here
A borrow is not ownership. If I borrow your car, I don't own your car.
Your real question is "why does it borrow it for the rest of the scope". Let's look at the signature:
fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Hash + Eq,
In words, this could be read as
Given a mutable reference to a
HashMap
(&mut self
) and something that can be used to find the key (K: Borrow<Q>, Q: Hash + Eq
), return a mutable reference to the value if one matches (Option<&mut V>
)
However, that returned mutable reference will be changing something in the HashMap
, that's why it's a mutable reference at all. You are only allowed to have multiple immutable borrows OR one mutable borrow at a time. This prevents writing code that causes inconsistencies and safety issues.
Let's look at remove
:
fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Hash + Eq,
This returns an owned value, not a reference into the HashMap
. Once the method is done, the borrow of the map is over.