如何在Rust中进行不借用的匹配?

3
我正在尝试编写康威生命游戏时,遇到了借用检查器的问题。我有两个for循环对self.cell_states进行可变借用,它是一个Vec>(CellState是一个枚举类型),以便我可以更新每个单元格的Alive或Dead状态。
然而,为了确定单元格应该是活着还是死了,它需要看看周围有多少细胞是活着的。这就是我遇到问题的地方。我能找到的唯一检查单元格是否存活的方法是使用match语句,但显然match会借用该值,这是不允许的,因为我已经进行了可变借用。在我看来,我只需复制该值并根据复制的值进行检查,因此我尝试了match self.cell_states[i+x-1][j+y-1].clone() {...},但无济于事。如何进行匹配而无需借用?
error[E0502]: cannot borrow `cell_states` as immutable because it is also borrowed as mutable
  --> src/main.rs:18:27
   |
11 |     for (i, row) in cell_states.iter_mut().enumerate() {
   |                     ----------------------------------
   |                     |
   |                     mutable borrow occurs here
   |                     mutable borrow used here, in later iteration of loop
...
18 |                     match cell_states[i+x-1][j+y-1] {
   |                           ^^^^^^^^^^^ immutable borrow occurs here

我的代码如下(Playground):
#[derive(Copy, Clone)]
pub enum CellState {
    Dead,
    Alive
}

fn main() {
    let mut cell_states = vec![vec![CellState::Dead; 10]; 10];


    for (i, row) in cell_states.iter_mut().enumerate() {
        for (j, cell) in row.iter_mut().enumerate() {
            // Count the living cells around cell
            let mut count = 0;

            for x in 0..3 {
                for y in 0..3 {
                    match cell_states[i+x-1][j+y-1] {
                        CellState::Alive => count += 1,
                        _ => ()
                    }
                }
            }
        }
    }
}
1个回答

6
我如何在Rust中进行无借用匹配?
你不能。每次访问变量时,都会发生借用。打印变量?那是借用。检查变量是否具有特定值?再次借用。复制变量的值?也是借用。
当您尝试访问向量的值时,该向量会被可变借用。这种情况行不通-- 借用检查器会禁止此操作。
您能否解决这个问题?可以!在使用向量或数组时的常规技巧是通过迭代索引来延迟所有借用。因此,请编写类似以下内容的代码:
for i in 0..cell_states.len() {
    for j in 0..cell_states[i].len() {
        ...
    }
}

在这种情况下,该向量没有被借用,但是您可以通过索引它来稍后借用其中的元素。

但是:借用检查器为您保存了,因为您尝试的方式存在错误!您尝试的不是生命游戏的工作方式!您需要两个单元格网格,因为更新步骤无法即时更新所有单元格。您首先需要将所有新单元格计算到一个新的向量中(以便在计算新值时可以使用所有旧的单元格值),然后可以用新的向量替换旧的向量。因此,生命游戏中的更新步骤是一个两步过程--您不能在原地完成它。

在修复了真正的错误之后,您会发现不会再遇到这个特定的借用检查器问题。


哇,那真是一个非常天真的方法,不是吗?我为尝试在原地完成它感到相当愚蠢。谢谢! - Michael Dorst
2
@MichaelDorst 不要难过!这是一个非常经典的错误:每个人在某个时候都可能犯过这样的错误。祝您继续愉快地学习 Rust! - Lukas Kalbertodt

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