使用其他 HashMap 中的值修改 HashMap,其键是从第一个 HashMap 借用的

问题描述 投票:0回答:1

假设我有两个

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
中,但我想知道是否没有更简单的方法。

rust borrow-checker
1个回答
0
投票

一般来说,不,编译器不能允许您

&mut
访问
m1
,因为您可以例如调用
.clear()
并销毁
m2
借用的值。

使用

Rc
作为按键对我来说似乎是一个明智的解决方案。

要考虑的另一个选项是对

Cell
的值使用内部可变类型(
RefCell
m1
),这将允许您在不
&mut
访问
m1
的情况下改变它们。由于值是数字,因此
Cell
可能是一个不错的选择,因为它没有像
RefCell
那样的引用计数开销。

© www.soinside.com 2019 - 2024. All rights reserved.