How can I borrow from a HashMap to read and write at the same time?

前端 未结 2 928
旧时难觅i
旧时难觅i 2020-12-02 02:42

I have a function f that accepts two references, one mut and one not mut. I have values for f inside a HashMap

2条回答
  •  伪装坚强ぢ
    2020-12-02 02:57

    TL;DR: You will need to change the type of HashMap


    When using a method, the compiler does not inspect the interior of a method, or perform any runtime simulation: it only bases its ownership/borrow-checking analysis on the signature of the method.

    In your case, this means that:

    • using get will borrow the entire HashMap for as long as the reference lives,
    • using get_mut will mutably borrow the entire HashMap for as long as the reference lives.

    And therefore, it is not possible with a HashMap to obtain both a &V and &mut V at the same time.


    The work-around, therefore, is to avoid the need for a &mut V entirely.

    This can be accomplished by using Cell or RefCell:

    • Turn your HashMap into HashMap>,
    • Use get in both cases,
    • Use borrow() to get a reference and borrow_mut() to get a mutable reference.
    use std::{cell::RefCell, collections::HashMap};
    
    fn main() {
        let mut map = HashMap::new();
    
        map.insert("1", RefCell::new(1));
        map.insert("2", RefCell::new(2));
    
        {
            let a = map.get("1").unwrap();
            println!("a: {}", a.borrow());
    
            let b = map.get("2").unwrap();
            println!("b: {}", b.borrow());
            *b.borrow_mut() = 5;
        }
    
        println!("Results: {:?}", map);
    }
    

    This will add a runtime check each time you call borrow() or borrow_mut(), and will panic if you ever attempt to use them incorrectly (if the two keys are equal, unlike your expectations).


    As for using fields: this works because the compiler can reason about borrowing status on a per-field basis.

提交回复
热议问题