'Cannot borrow value from a hashmap as mutable because it is also borrowed as immutable

I want to get two values from a hashmap at the same time, but I can't escape the following error, I have simplified the code as follows, can anyone help me to fix this error.

#[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);
    
        }
    }
}

Playground

error[E0502]: cannot borrow hash as mutable because it is also borrowed as immutable

  --> 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

For more information about this error, try rustc --explain E0502. error: could not compile playground due to previous error



Solution 1:[1]

Since the keys to the hash table are the integers 0..100 you can use a Vec to perform these steps, temporarily splitting the Vec into 2 slices to allow the mutation on one side. If you need a HashMap for later computations, you can then create a HashMap from the Vec.

The following code compiles but panics because the j - 10 calculation underflows:

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 main() {
    let size = 100;
    let mut v: Vec<Option<Vec<usize>>> = vec![None; size];
    for i in 0..size {
        let (v1, v2) = v.split_at_mut(i + 1);
        if v1[i].is_none() {
            v1[i] = Some(vec![1,2,3]);
        }
        let data1 = v1[i].as_ref().unwrap();

        for (j, item) in (i + 1..).zip(v2.iter_mut()) {
            if do_check(i, j) {
                break
            }
            if item.is_none() {
                *item = Some(vec![1,2,3]);
            }
            let data2 = item.as_ref().unwrap();
            let res = do_cal(data1, data2);
            println!("res:{}", res);

        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jonathan Giddy