Suppose I have two HashMap
s, m1
and m2
with the same set of non-Copy
keys, except m2
’s keys are borrowed from m1
(say, m1
has String
keys and m2
has &str
keys borrowed from m1
). Is it possible to iterate through m1
and update its values using the corresponding values from m2
? The compiler believes that since m2
borrows (immutably) from m1
, borrowing m1
mutably (say, through iter_mut()
or get_mut()
) should not be allowed.
Here is an MVE, demonstrating two attempts at iteration:
use std::collections::HashMap;
fn main() {
let mut m1 = HashMap::<_, _>::from_iter([("a".to_owned(), 1), ("b".to_owned(), 2)]);
let m2 = m1
.iter()
.map(|(k, v)| (k.as_str(), v))
.collect::<HashMap<_, _>>();
for (k, v) in m1.iter_mut() {
*v += m2[k.as_str()];
}
for (&k, &v) in m2.iter() {
*m1.get_mut(k).unwrap() += v;
}
}
error[E0502]: cannot borrow `m1` as mutable because it is also borrowed as immutable
--> src/main.rs:10:16
|
5 | let m2 = m1
| -- immutable borrow occurs here
...
10 | for (k, v) in m1.iter_mut() {
| ^^^^^^^^^^^^^ mutable borrow occurs here
11 | *v += m2[k.as_str()];
| -- immutable borrow later used here
error[E0502]: cannot borrow `m1` as mutable because it is also borrowed as immutable
--> src/main.rs:15:4
|
5 | let m2 = m1
| -- immutable borrow occurs here
...
14 | for (&k, &v) in m2.iter() {
| --------- immutable borrow later used here
15 | *m1.get_mut(k).unwrap() += v;
| ^^^^^^^^^^^^^ mutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
I believe that what I'm trying to do is sound because modifying existing values of a HashMap
won't cause any of its keys to move, and so m2
’s references to m1
’s keys will remain valid. But it doesn't seem possible to express this to the compiler?
I've considered using Rc<String>
keys or just usize
and storing the String
s in a Vec
, but I'm wondering if there's not a simpler way.
Generally speaking, no, the compiler cannot allow you &mut
access to m1
because you could e.g. invoke .clear()
and destroy the values that are being borrowed by m2
.
Using Rc
for the keys seems like a sensible solution to me.
Another option to consider would be using an interior mutability type (Cell
or RefCell
) for m1
's values, which would allow you to mutate them without &mut
access to m1
. Since the values are numbers, Cell
is probably a good fit since it has no reference-counting overhead like RefCell
does.