Неизменяемое заимствование, связанное с изменяемым заимствованием, приводит к тому, что «невозможно заимствовать `*self` как изменяемое более одного раза за раз»

Я изучаю Rust упражнениями. Целью этого файла является обновление ячеек, как в электронной таблице: при изменении значения все ячейки, производные от него, должны быть пересчитаны. Здесь они называются родителями этой ячейки.

Обновление значения ячейки не вызывает проблем, но обновление родителей заставляет меня бороться с проверкой заимствования. Когда я получил ячейку из HashMap и обновил значение, мне больше не нужна изменяемая ссылка, поэтому вместо этого я попытался обернуть ее неизменяемой ссылкой. Таким образом, мне нужно найти его только один раз.

Но, похоже, Rust фигурирует, поскольку я изначально получил свою неизменяемую ссылку от заимствованного &mut self, он все еще должен быть привязан к нему. Это, очевидно, не позволяет мне повторно использовать self во второй раз.

use std::collections::HashMap;
use std::vec::Vec;

struct Cell {
    value: i32,
    parents: Vec<u32>,
}

pub struct Sheet {
    table: HashMap<u32, Cell>,
}

impl Sheet {
    pub fn set_value(&mut self, identifier: u32, new_value: i32) {
        let mut updated_cell: Option<&Cell> = None;
        if let Some(cell) = self.table.get_mut(&identifier) {
            let Cell { value, .. } = cell;
            *value = new_value;
            updated_cell = Some(cell);
        }
        if let Some(cell) = updated_cell {
            recalculate(self, &cell.parents);
        }
    }
}

fn recalculate(_sheet: &mut Sheet, _cells: &[u32]) {}
error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/lib.rs:20:16
   |
16 |         if let Some(cell) = self.table.get_mut(&identifier) {
   |                             ---------- first mutable borrow occurs here
...
22 |             recalculate(self, &cell.parents);
   |                         ^^^^  ------------- first borrow later used here
   |                         |
   |                         second mutable borrow occurs here

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

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

Ответы 1

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

Rust защищает вас от потенциально опасной ситуации. В подписи recalculate нет ничего, что гарантировало бы, что она не изменится sheet таким образом, что ссылки в cells станут недействительными. Например, recalculateмог удалит некоторые ячейки, и тогда ссылки в cell.parents будут оборванными указателями.

Вместо этого вам, вероятно, нужно передать клон родительских ячеек:

if let Some(cell) = updated_cell {
    let parents = cell.parents.clone();
    recalculate(self, &parents);
}

В качестве альтернативы вам может потребоваться рассмотреть другую модель данных, которая отделяет изменчивость отдельных ячеек от изменчивости всей структуры. Например, вы можете заключить ячейки в std::cell::Cell или std::cell::RefCell и передать неизменяемую ссылку на Sheet.

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

Похожие вопросы

Как определить аннотацию типа при вызове MyActor::from_registry() из обработчика другого актора, который не определяет T?
Как изменить значение Arc<u64> в структуре?
Почему библиотека WASM в Rust должна устанавливать тип контейнера как cdylib?
Могу ли я десериализовать векторы с префиксом переменной длины с помощью Bincode?
Возврат замыкания из замыкания в качестве возвращаемого значения для функции
Сообщает ли компилятору, возвращающему тип со значением 'static, что это значение не имеет связанного времени жизни, или оно делает это значение статическим?
Как я могу реализовать сложные макросы, такие как `format_args!`, в пользовательском пространстве?
Простая реализация для получения итератора первого слова каждой строки ввода
Как кросс-компилировать код Rust для Raspberry Pi Zero W
Передача String::as_str в Option<String>::map() не компилируется с ошибкой несоответствия типов