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.
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 }}
*/