Я пытаюсь найти лучший способ обработки некоторых вложенных изменяемых изменений. У меня есть следующий код, который имитирует проблему, с которой я столкнулся:
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);
}
});
}
Вы можете игнорировать данные, введенные в хеш — я просто помещаю туда фиктивные данные. На самом деле это пользовательская структура, и мне нужно изменить элементы внутри структуры. Код ниже дает точно такую же ошибку компилятора, поэтому я думаю, что этого примера достаточно.
Каков наилучший способ перебора хеша, чтобы я мог изменять данные по мере необходимости? Компилятор предлагает добавить &
в начало хеша, но это тоже не решает проблему. Наверное, я смотрю на это неправильно. Предложения будут очень признательны.
Ну вот:
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 for ... in
циклы немного сложны, потому что многие вещи происходят неявно. Если вы хотите быть более ясным, вы можете заменить &mut hash
на hash.iter_mut()
.
Добавить
&mut
вместо&
?