Why does HashMap :: get_mut () take responsibility for the map for the rest of the area?

I have the following code that inserts some values โ€‹โ€‹into a HashMap and then returns them:

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); } 

Attempting to compile this code gives the following error:

 error[E0499]: cannot borrow `map` as mutable more than once at a time --> src/main.rs:10:21 | 9 | let mut world = map.get_mut(&4); | --- first mutable borrow occurs here 10 | let mut hello = map.get_mut(&1); | ^^^ second mutable borrow occurs here 11 | } | - first borrow ends here 

After looking at the API documents for the remove() and get_mut() fortunately, they are pretty close to each other!) There is nothing that stands out to me from the method signatures, why the remove() method cannot easily borrow a map for the rest of the current areas, while the get_mut() method does.

The other part of the data that I have also puzzles me that this code compiles:

 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); map.get_mut(&4); let mut hello = map.get_mut(&1); } 

Do not save the result of the first call to get_mut() does not cause the map to be borrowed for the rest of the region? How could I find out about this by looking at the documentation? Did I miss something?

+6
source share
1 answer

The great news is that this error is ultimately a limitation on the current implementation of the borrower controller. A future version of Rust will introduce non-sex lifetimes. With the included functions, the source code will work as is:

 #![feature(nll)] 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 will be smarter and can see that you are no longer using world at the time map.get_mut(&1) received, so it no longer needs to have a valid link.

You can get the equivalent code in the current version 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 HashMap::get_mut() take responsibility for the map

Absolutely it does not . Ownership is the exact term in the rust code. Please note that the error message states

previous map borrowing takes place here

The loan is not property. If I borrow my car, I donโ€™t have my own car.

Your real question is: "Why does he borrow it for the rest of the realm." 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 can be read as

Given the variable reference to the HashMap ( &mut self ) and something that can be used to find the key ( K: Borrow<Q>, Q: Hash + Eq ), return a mutable link to the value if it matches ( Option<&mut V> )

However, the returned mutable link will change something in the HashMap , so this is the link in general. You are only allowed to have a few immutable borrowings or one variable borrower at a time. This prevents code writing that causes inconsistencies and security issues.

Take a look at remove :

 fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> where K: Borrow<Q>, Q: Hash + Eq, 

This returns the value that belongs to it, and not the link in the HashMap . As soon as the method is completed, the borrowing of the card is completed.

+8
source

All Articles