不可变的借用和可变的借用绑定导致了“无法同时多次可变地借用`*self`”错误。

9
我正在通过练习学习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

我想知道是否有一种解决方案,可以避免第二次搜索或进行不必要的向量复制。我已经尝试过多次调整代码,但并不是所有的语法都清楚明了。

1个回答

3
Rust在保护您免受潜在危险。 在recalculate的签名中没有任何东西可以保证它不会以使cells中的引用无效的方式改变sheet。例如,recalculate可能会删除某些单元格,然后cell.parents中的引用将成为悬挂指针。
您可能需要传递父单元格的克隆版本:
if let Some(cell) = updated_cell {
    let parents = cell.parents.clone();
    recalculate(self, &parents);
}

或许您需要考虑另一种数据模型,它将单元格的可变性与整体结构的可变性分离。例如,您可以使用 std::cell::Cellstd::cell::RefCell 来包装单元格,并向 Sheet 传递一个不可变引用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接