Лучший способ иметь вложенный изменяемый элемент данных в Rust

Я пытаюсь найти лучший способ обработки некоторых вложенных изменяемых изменений. У меня есть следующий код, который имитирует проблему, с которой я столкнулся:

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

    });

}

Вы можете игнорировать данные, введенные в хеш — я просто помещаю туда фиктивные данные. На самом деле это пользовательская структура, и мне нужно изменить элементы внутри структуры. Код ниже дает точно такую ​​же ошибку компилятора, поэтому я думаю, что этого примера достаточно.

Каков наилучший способ перебора хеша, чтобы я мог изменять данные по мере необходимости? Компилятор предлагает добавить & в начало хеша, но это тоже не решает проблему. Наверное, я смотрю на это неправильно. Предложения будут очень признательны.

Добавить &mut вместо &?

Finomnis 09.07.2024 07:30
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
1
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ну вот:

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 генерирует:
    • key: &u8
    • value: &mut CircularBuffer<200, f32>
  • let first = &mut value[0]; генерирует:
    • first: &mut f32

Затем, чтобы отредактировать изменяемую ссылку, вам нужно разыменовать ее с помощью *first =.

Основное различие между использованием f32 и пользовательской структурой заключается в том, что f32 — это Copy, поэтому вам нужно быть осторожным и следить за тем, чтобы вы действительно редактировали исходный объект, а не копию. Вот почему важно, чтобы first был &mut f32, а не mut f32.

Дополнительные советы

Используйте IDE, например VSCode , вместе с расширением rus-analyzer. Это показывает вам все типы в строке, что позволяет легко понять, что происходит:

Спасибо за очень подробный ответ! Я использую RustRover, поэтому могу видеть, что происходит. Я запутался в том, где на самом деле должна находиться моя изменчивость, и мне никогда не приходило в голову использовать &mut на этом уровне. Огромное спасибо за помощь!

PilotGuy 09.07.2024 15:46

@PilotGuy for ... in циклы немного сложны, потому что многие вещи происходят неявно. Если вы хотите быть более ясным, вы можете заменить &mut hash на hash.iter_mut().

Finomnis 09.07.2024 17:02

Другие вопросы по теме