Why does HashMap::get_mut() take ownership of the map for the rest of the scope?

前端 未结 1 1966
有刺的猬
有刺的猬 2021-01-11 16:39

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          


        
相关标签:
1条回答
  • 2021-01-11 17:21

    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.

    0 讨论(0)
提交回复
热议问题