I'm trying to figure out the best way to handle some nested mutable changes. I've got the following code that mimicks the issue I'm running into:
use std::collections::HashMap;
use circular_buffer::CircularBuffer;
#[tokio::main]
async fn main() {
let mut hash:HashMap<u8, CircularBuffer<200, f32>> = HashMap::new();
for idx in 0..10 {
let mut buffer = CircularBuffer::<200, f32>::new();
buffer.push_front(14.0 * idx as f32 + 2.0);
buffer.push_front(19.4 * idx as f32 + 4.19);
hash.insert(idx, buffer);
}
tokio::spawn(async move {
for (key, mut value) in hash {
println!("key: {}, buffer_length: {}", key, value.len());
let mut first = value[0];
first = 24.0 * key as f32;
}
for (key, mut value) in hash {
println!("key: {}, buffer_length: {}", key, value.len());
let mut first = value[0];
println!("\tFirst: {}", first);
}
});
}
You can ignore the data entered into the hash -- I'm just putting dummy data there. In reality, it's a custom struct, and I need to modify items inside the structs. The code below gives the exact same compiler error, so I think the example is sufficient.
What's the best way to iterate through hash so that I can modify the data as needed? The compiler suggests adding an &
to the beginning of hash, but that doesn't really resolve the issue, either. I'm probably looking at this incorrectly. Suggestions would be very much appreciated.
Here you go:
use circular_buffer::CircularBuffer;
use std::collections::HashMap;
#[tokio::main]
async fn main() {
let mut hash: HashMap<u8, CircularBuffer<200, f32>> = HashMap::new();
for idx in 0..10 {
let mut buffer = CircularBuffer::<200, f32>::new();
buffer.push_front(14.0 * idx as f32 + 2.0);
buffer.push_front(19.4 * idx as f32 + 4.19);
hash.insert(idx, buffer);
}
let task = tokio::spawn(async move {
for (key, value) in &mut hash {
println!("key: {}, buffer_length: {}", key, value.len());
let first = &mut value[0];
*first = 24.0 * *key as f32;
}
for (key, value) in &mut hash {
println!("key: {}, buffer_length: {}", key, value.len());
let first = value[0];
println!("\tFirst: {}", first);
}
});
task.await.unwrap();
}
key: 6, buffer_length: 2
key: 4, buffer_length: 2
key: 7, buffer_length: 2
key: 8, buffer_length: 2
key: 5, buffer_length: 2
key: 3, buffer_length: 2
key: 0, buffer_length: 2
key: 2, buffer_length: 2
key: 9, buffer_length: 2
key: 1, buffer_length: 2
key: 6, buffer_length: 2
First: 144
key: 4, buffer_length: 2
First: 96
key: 7, buffer_length: 2
First: 168
key: 8, buffer_length: 2
First: 192
key: 5, buffer_length: 2
First: 120
key: 3, buffer_length: 2
First: 72
key: 0, buffer_length: 2
First: 0
key: 2, buffer_length: 2
First: 48
key: 9, buffer_length: 2
First: 216
key: 1, buffer_length: 2
First: 24
for (key, value) in &mut hash
generates:
key: &u8
value: &mut CircularBuffer<200, f32>
let first = &mut value[0];
generates:
first: &mut f32
Then, to edit a mutable reference, you need to dereference it via *first =
.
The main difference between using f32
and a custom struct is that f32
is Copy
, so you need to be careful that you actually edit the original object and not a copy. That's why it's important that first
is &mut f32
and not mut f32
.
Use an IDE like VSCode together with the rust-analyzer extension. That shows you all the types inline, making it very easy to understand what's going on: