假设我有两个
HashMap
,m1
和m2
,具有相同的一组非Copy
键,除了m2
的键是从m1
借来的(比如说,m1
有) String
键和 m2
有从 &str
借来的 m1
键)。是否可以迭代 m1
并使用 m2
中的相应值更新其值?编译器认为,由于 m2
从 m1
借用(不可变),因此不允许可变地借用 m1
(例如,通过 iter_mut()
或 get_mut()
)。
这是一个 MVE,演示了两种迭代尝试:
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`.
我相信我正在尝试做的事情是合理的,因为修改
HashMap
的现有值不会导致其任何键移动,因此 m2
对 m1
的键的引用将保留有效的。但似乎无法向编译器表达这一点?
我考虑过使用
Rc<String>
键或仅使用 usize
并将 String
存储在 Vec
中,但我想知道是否没有更简单的方法。
一般来说,不,编译器不能允许您
&mut
访问 m1
,因为您可以例如调用 .clear()
并销毁 m2
借用的值。
使用
Rc
作为按键对我来说似乎是一个明智的解决方案。
要考虑的另一个选项是对
Cell
的值使用内部可变类型(RefCell
或 m1
),这将允许您在不 &mut
访问 m1
的情况下改变它们。由于值是数字,因此 Cell
可能是一个不错的选择,因为它没有像 RefCell
那样的引用计数开销。