我正在通过运动来学习锈蚀。在此文件中,目标是像电子表格中更新单元格:当值变化时,所有从其衍生的单元都必须重新计算。在这里,这些被称为牢房的父母。
更新单元格值证明没有问题,但是更新父母会让我与借用检查器作斗争。当我从HashMap
检索单元格并更新了该值时,我不再需要可变的参考 - 因此我尝试将其包装在不变的参考文献中。这样,我只需要一次找到一次。
,但似乎是生锈的数字,因为我最初从借来的&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
我想知道是否有解决方案可以避免第二次搜索或进行不必要的矢量副本。我已经尝试多次调整代码,但并非所有语法对我来说都很清楚。
锈病正在保护您免受潜在危险的情况。recalculate
的签名中没有任何东西可以保证它不会以cells
中的参考文献无效而突变sheet
。例如, recalculate
可以删除某些单元格,然后 cell.parents
中的引用将悬挂。
您可能需要通过父单元的克隆:
if let Some(cell) = updated_cell {
let parents = cell.parents.clone();
recalculate(self, &parents);
}
另外,您可能需要考虑一个不同的数据模型,这将单个细胞的突变性与整体结构的可突变性分开。例如,您可以将单元格包裹在std::cell::Cell
或std::cell::RefCell
中,然后将不变的引用传递给Sheet
。