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