Я пытался изучить Rust, разрабатывая небольшие программы, однако кривая обучения оказалась более крутой, чем я думал.
Я играл со следующим фрагментом кода, который не работает из-за ошибки компилятора заимствования.
Это простая программа, в которой у вас есть словарь пользовательских объектов. В зависимости от некоторых условий некоторые значения будут изменены, а другие будут удалены из словаря.
use std::collections::HashMap;
// Define the Custom struct
pub struct Custom {
x: u8,
}
fn main() {
// Create a HashMap with string keys and Custom objects as values
let mut custom_map: HashMap<String, Custom> = HashMap::new();
// Insert some sample data into the map
custom_map.insert("apple".to_string(), Custom { x: 10 });
custom_map.insert("banana".to_string(), Custom { x: 20 });
custom_map.insert("grape".to_string(), Custom { x: 30 });
custom_map.insert("quince".to_string(), Custom { x: 40 }); // Example entry with 'q'
let mut elements_to_be_deleted: Vec<&String> = Vec::new();
// Iterate over the keys and values in the map
for (key, custom) in &mut custom_map {
if key.contains('a') {
// Increment the x property for keys containing 'a'
custom.x += 1;
}
if key.contains('q') {
// Remove entries with 'q' from the map
elements_to_be_deleted.push(key);
}
}
// iterate over the keys that need to be deleted
for key in &elements_to_be_deleted {
custom_map.remove(*key);
}
// Print the updated values
for (key, custom) in &custom_map {
println!("Key: {}, x: {}", key, custom.x);
}
}
Ошибка компилятора следующая:
|
21 | for (key, custom) in &mut custom_map {
| --------------- first mutable borrow occurs here
34 | for key in &elements_to_be_deleted {
| ----------------------- first borrow later used here
35 | custom_map.remove(*key);
| ^^^^^^^^^^ second mutable borrow occurs here
Хорошо, я понимаю, я не могу иметь в одном жизненном цикле и саму изменяемую переменную, и изменяемую ссылку на нее.
Я изменил приведенный выше код и вынес операции мутации в отдельные функции.
use std::collections::HashMap;
// Define the Custom struct
pub struct Custom {
x: u8,
}
fn main() {
// Create a HashMap with string keys and Custom objects as values
let mut custom_map: HashMap<String, Custom> = HashMap::new();
// Insert some sample data into the map
custom_map.insert("apple".to_string(), Custom { x: 10 });
custom_map.insert("banana".to_string(), Custom { x: 20 });
custom_map.insert("grape".to_string(), Custom { x: 30 });
custom_map.insert("quince".to_string(), Custom { x: 40 }); // Example entry with 'q'
let mut elements_to_be_deleted: Vec<&String> = Vec::new();
// Iterate over the keys and values in the map
for (key, custom) in &custom_map {
if key.contains('q') {
// Remove entries with 'q' from the map
elements_to_be_deleted.push(&key);
}
}
// modify map elements
modifyMapElements(&mut custom_map);
//delete map elements
deleteElementsFromMap(&mut custom_map, elements_to_be_deleted);
// Print the updated values
for (key, custom) in &custom_map {
println!("Key: {}, x: {}", key, custom.x);
}
}
fn deleteElementsFromMap(map: &mut HashMap<String, Custom>, els_to_delete: Vec<&String>) {
for key in elements_to_be_deleted {
map.remove(&key);
}
}
fn modifyMapElements(map: &mut HashMap<String, Custom>) {
for (key, custom) in map {
if key.contains('a') {
// Increment the x property for keys containing 'a'
custom.x += 1;
}
}
}
Ошибка компилятора этого фрагмента такова:
for (key, custom) in &custom_map {
| ----------- immutable borrow occurs here
...
32 | deleteElementsFromMap(&mut custom_map, elements_to_be_deleted);
| ^^^^^^^^^^^^^^^ ---------------------- immutable borrow later used here
| |
| mutable borrow occurs here
Я попытался заключить цикл for, который неизменно перебирает карту, в отдельный блок, но он ничего не решает.
{
// Iterate over the keys and values in the map
for (key, custom) in &custom_map {
if key.contains('q') {
// Remove entries with 'q' from the map
elements_to_be_deleted.push(&key);
}
}
}
Я понимаю, вы не можете иметь изменяемые и неизменяемые ссылки на переменную в одних и тех же областях.
Мой вопрос: как спроектировать приведенный выше код, чтобы использовать справочную систему Rust в своих интересах? Мне как разработчику Rust больше интересно научиться думать и проектировать этот фрагмент кода, поэтому меня не особо интересуют обходные пути.
Вы можете использовать HashMap::retain для перебора и удаления в одном цикле.
use std::collections::HashMap;
// Define the Custom struct
pub struct Custom {
x: u8,
}
fn main() {
// Create a HashMap with string keys and Custom objects as values
let mut custom_map: HashMap<String, Custom> = HashMap::new();
// Insert some sample data into the map
custom_map.insert("apple".to_string(), Custom { x: 10 });
custom_map.insert("banana".to_string(), Custom { x: 20 });
custom_map.insert("grape".to_string(), Custom { x: 30 });
custom_map.insert("quince".to_string(), Custom { x: 40 }); // Example entry with 'q'
// Iterate over the keys and values in the map
custom_map.retain(|key, custom| {
if key.contains('a') {
// Increment the x property for keys containing 'a'
custom.x += 1;
}
// Only retain entries with no 'q'
!key.contains('q')
});
// Print the updated values
for (key, custom) in &custom_map {
println!("Key: {}, x: {}", key, custom.x);
}
}