0

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.

1
  • Add &mut instead of &? Commented Jul 9, 2024 at 5:30

1 Answer 1

2

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

Explanation

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

Additional Tips

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:

rust-analyzer type annotations

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the very thorough response! I've been using RustRover, so I can see what's going on. I was getting lost on where my mutability should really reside -- and it never occurred to me to use &mut at that level. Thank you so much for the assist!
@PilotGuy for ... in loops are a little tricky, because a lot of stuff happens implicitly. If you want to be explicit, you can replace &mut hash with hash.iter_mut().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.