1

This is a simplified version of code that I written for a leetcode question. In the problem from leetcode I have an immutable input like aux_vec_i32 below and I need to return something more complicated than in the sample code below, but the compiler errors are similar between the leetcode stuff I wrote and what is below. In the end hmap_for_data should hold the counts of unique counts of items in aux_vec_i32.

The current incantation of '&', 'mut', '*' and 'as' strewn in the code is the result of me fighting the compiler and not achieving success by following its suggestions.

use std::collections::HashMap;

fn main(){
    struct Data{
        the_data: i32,
    }
    let aux_vec_i32 = vec![1, 2, 3, 1];
    let mut hmap_for_data: HashMap<i32, Data>=HashMap::new();

    for i in &aux_vec_i32 {
        match hmap_for_data.get(&mut aux_vec_i32[*i as usize]) {
            None => {
                hmap_for_data.insert(
                    aux_vec_i32[*i as usize], 
                    Data {
                        the_data: 1,
                    }
                );
            }
            Some(mut data_to_increment) => {
                data_to_increment.the_data += 1;
            }
        }
    }
}
error[E0502]: cannot borrow `aux_vec_i32` as mutable because it is also borrowed as immutable
  --> src/main.rs:11:38
   |
10 |     for i in &aux_vec_i32 {
   |              ------------
   |              |
   |              immutable borrow occurs here
   |              immutable borrow later used here
11 |         match hmap_for_data.get(&mut aux_vec_i32[*i as usize]) {
   |                                      ^^^^^^^^^^^ mutable borrow occurs here

error[E0596]: cannot borrow `aux_vec_i32` as mutable, as it is not declared as mutable
  --> src/main.rs:11:38
   |
11 |         match hmap_for_data.get(&mut aux_vec_i32[*i as usize]) {
   |                                      ^^^^^^^^^^^ cannot borrow as mutable
   |
help: consider changing this to be mutable
   |
7  |     let mut aux_vec_i32 = vec![1, 2, 3, 1];
   |         +++

error[E0594]: cannot assign to `data_to_increment.the_data`, which is behind a `&` reference
  --> src/main.rs:21:17
   |
20 |             Some(mut data_to_increment) => {
   |                  --------------------- consider changing this binding's type to be: `&mut Data`
21 |                 data_to_increment.the_data += 1;
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `data_to_increment` is a `&` reference, so the data it refers to cannot be written

Here is a link to the playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=535206613151ae0e4507296cf816d2a0.

4
  • Please post the full error from cargo check in the question. Commented Jul 4 at 21:06
  • Please post all, full errors from the snippet. Commented Jul 4 at 21:09
  • Actually I bungled the sample code, it doesn't do anything useful, I'll come back with an edit.
    – branco
    Commented Jul 4 at 21:40
  • Edit: the accepted answer is what I'll study tomorrow to fix my leetcode stuff.
    – branco
    Commented Jul 4 at 21:47

1 Answer 1

1

Here is the modified code, in order to make it pass compilation.

Taking an element of aux_vec_i32 does not need &mut.

In order to increment an element of hmap_for_data, we need .get_mut() instead of .get().

Another formulation is possible with the .entry() API.

To be honest, I don't understand what this does since there is a kind of mix between indices and content in the vector...

use std::collections::HashMap;

fn main() {
    #[derive(Debug)]
    struct Data {
        the_data: i32,
    }
    let aux_vec_i32 = vec![1, 2, 3, 1];
    let mut hmap_for_data: HashMap<i32, Data> = HashMap::new();

    for i in &aux_vec_i32 {
        if false {
            // original solution
            match hmap_for_data.get_mut(&aux_vec_i32[*i as usize]) {
                None => {
                    hmap_for_data.insert(
                        aux_vec_i32[*i as usize],
                        Data { the_data: 1 },
                    );
                }
                Some(data_to_increment) => {
                    data_to_increment.the_data += 1;
                }
            }
        } else {
            // using the  .entry()  API
            hmap_for_data
                .entry(aux_vec_i32[*i as usize])
                .and_modify(|e| e.the_data += 1)
                .or_insert_with(|| Data { the_data: 1 });
        }
    }
    println!("{:?}", hmap_for_data);
}
/*
{1: Data { the_data: 1 }, 3: Data { the_data: 1 }, 2: Data { the_data: 2 }}
*/
0

Not the answer you're looking for? Browse other questions tagged or ask your own question.