无法从哈希映射中借用可变的值,因为它也借用为不可变的

Moo*_*old 1 hashmap rust

我想同时从哈希图中获取两个值,但我无法逃避以下错误,我已将代码简化如下,任何人都可以帮助我修复此错误。

#[warn(unused_variables)]
use hashbrown::HashMap;

fn do_cal(a: &[usize], b: &[usize]) -> usize {
    a.iter().sum::<usize>() + b.iter().sum::<usize>()
}

fn do_check(i: usize, j:usize) -> bool {
    i/2 < j - 10
}

fn do_expensive_cal(i: usize) -> Vec<usize> {
    vec![i,i,i]
}

fn main() {
    let size = 1000000;
    let mut hash: HashMap<usize, Vec<usize>> = HashMap::new();
    for i in 0..size{
        if i > 0 {
            hash.remove(&(i - 1));
        }
        
        if !hash.contains_key(&i){
            hash.insert(i, do_expensive_cal(i));
        }
        let data1 = hash.get(&i).unwrap();
    
        for j in i + 1..size {
            if do_check(i, j) {
                break
            }
            if !hash.contains_key(&j){
                hash.insert(j, do_expensive_cal(j));
            }
            let data2 = hash.get(&j).unwrap();
            let res = do_cal(data1, data2);
            println!("res:{}", res);
    
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

操场

错误[E0502]:无法hash作为可变借用,因为它也作为不可变借用

  --> src/main.rs:26:8
   |
19 |         let data1 = hash.get(&i).unwrap();
   |                     ------------ immutable borrow occurs here
...
26 |                 hash.insert(j, vec![1,2,3]);
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
29 |             let res = do_cal(data1, data2);
   |                              ----- immutable borrow later used here
Run Code Online (Sandbox Code Playgroud)

有关此错误的更多信息,请尝试rustc --explain E0502playground错误:由于之前的错误而无法编译

Cae*_*sar 6

考虑一下:借用检查器不知道这hash.insert(j, \xe2\x80\xa6)会留下您插入的数据hash.insert(i, \xe2\x80\xa6)。对于借用检查器,hash.insert(\xe2\x80\xa6)可以对 中的任何元素执行任何操作hash,包括重写或删除它。因此,您不能被允许将引用保留data1在 上hash.insert(j, \xe2\x80\xa6)

\n

如何克服这个问题?最简单的可能是移动,let data1 = hash.get(\xe2\x80\xa6)这样它就不必存活这么久:

\n
let data1 = hash.get(&i).unwrap();\nlet data2 = hash.get(&j).unwrap();\nlet res = do_cal(data1, data2);\n
Run Code Online (Sandbox Code Playgroud)\n

当然,这将查找data1每个循环迭代(并且它必须,因为hash.insert(j, \xe2\x80\xa6)可能已经调整了大小,从而重新分配了哈希映射的内容,从而data1在哈希映射中给出了新的存储位置)。为了完整起见,有一些方法可以解决这个问题,但我不建议您这样做:

\n
    \n
  • 克隆:(let data1 = hash.get(&i).unwrap().clone()如果你的向量很短,这实际上可能是合理的\xe2\x80\xa6)
  • \n
  • 作为一种使克隆变得便宜的方法,您可以使用 aHashMap<usize, Rc<Vec<usize>>>代替(您只需要克隆Rc,而不是整个Vec
  • \n
  • 如果您需要对 的两个参数进行可变引用do_call,您可以将Rc与 a结合起来RefCellRc<RefCell<Vec<\xe2\x80\xa6>>>
  • \n
  • 如果您需要对其进行更多的过度设计,您可以将Rcs 替换为从凹凸分配器中分配所获得的引用,例如凹凸分配器
  • \n
\n