Ошибка множественного заимствования для простого приложения

Я пытался изучить 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 больше интересно научиться думать и проектировать этот фрагмент кода, поэтому меня не особо интересуют обходные пути.

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

Ответы 1

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

Вы можете использовать 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);
    }
}

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