How can I borrow from a HashMap to read and write at the same time?
Solution 1:
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 entireHashMap
for as long as the reference lives, - using
get_mut
will mutably borrow the entireHashMap
for as long as the reference lives.
And therefore, it is not possible with a HashMap<K, V>
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
intoHashMap<K, RefCell<V>>
, - Use
get
in both cases, - Use
borrow()
to get a reference andborrow_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.
Solution 2:
Something appears to have changed since the question was asked. In Rust 1.38.0 (possibly earlier), the following compiles and works:
use std::collections::HashMap;
fn f(a: &i32, b: &mut i32) {}
fn main() {
let mut map = HashMap::new();
map.insert("1", 1);
map.insert("2", 2);
let a: &i32 = map.get("1").unwrap();
println!("a: {}", a);
let b: &mut i32 = map.get_mut("2").unwrap();
println!("b: {}", b);
*b = 5;
println!("Results: {:?}", map)
}
playground
There is no need for RefCell
, nor is there even a need for the inner scope.