根据同一个 Hashmap 中的另一个值插入到一个 HashMap 中

Insert into a HashMap based on another value in the same Hashmap

我正在尝试根据同一 HashMap 中的另一个值将一个值插入到 HashMap 中,如下所示:

use std::collections::HashMap;

fn main() {
    let mut some_map = HashMap::new();
    some_map.insert("a", 1);

    let some_val = some_map.get("a").unwrap();

    if *some_val != 2 {
        some_map.insert("b", *some_val);
    }
}

发出此警告:

warning: cannot borrow `some_map` as mutable because it is also borrowed as immutable
  --> src/main.rs:10:9
   |
7  |     let some_val = some_map.get("a").unwrap();
   |                    -------- immutable borrow occurs here
...
10 |         some_map.insert("b", *some_val);
   |         ^^^^^^^^             --------- immutable borrow later used here
   |         |
   |         mutable borrow occurs here
   |
   = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
   = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
   = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>

如果我改为尝试 更新 现有值,我可以使用内部突变和 RefCell,如 所述。

如果我尝试插入 更新基于 自身 的值,我可以使用条目 API,如所述 .

我可以通过克隆来解决这个问题,但我宁愿避免这种情况,因为在我的实际代码中检索到的值有些复杂。这需要不安全的代码吗?

编辑 由于之前的答案完全是错误的,根本没有回答问题,所以有代码没有显示任何警告 (playground)

现在它是一个具有 Rc<_> 个值的散列图,val_rc 仅包含实际数据的引用计数器(在本例中为 1)。因为它只是一个计数器,所以没有克隆它的成本。但是请注意,只有一个数字副本存在,因此如果您修改 some_map["a"] 的值,那么 some_map["b"] 也会被修改,因为它们指的是一块内存。另请注意,1 存在于堆栈中,因此如果您打算添加许多重对象,最好考虑将其转换为 Rc<Box<_>>

use std::collections::HashMap;
use std::rc::Rc;

fn main() {
    let mut some_map = HashMap::new();
    some_map.insert("a", Rc::new(1));

    let val_rc = Rc::clone(some_map.get("a").unwrap());
    if *val_rc != 2 {
        some_map.insert("b", val_rc);
    }

}

上一个答案

很难说出你到底在找什么,但在这种特殊情况下,如果你只需要检查值,那么在更新 hashmap 之前销毁借用的值。一个又脏又丑的代码会是这样的:

fn main() {
    let mut some_map = HashMap::new();
    some_map.insert("a", 1);

    let is_ok = false;

    {
        let some_val = some_map.get("a").unwrap();
        is_ok = *some_val != 2;
    }

    if is_ok {
        some_map.insert("b", *some_val);
    }
}