首页 > 解决方案 > 如何在方法中获取对结构字段的可变引用并调用其他方法而不会引起借用检查器的抱怨?

问题描述

我有这个代码:

struct Player {}

impl Player {
    fn update(&mut self) {}
}

struct GameBoard {
    p1: Player,
    p2: Player,
}

impl GameBoard {
    fn update(&mut self) {}
    fn update_current_player(&mut self, p1_turn: bool) {
        if p1_turn {
            self.p1.update()
        } else {
            self.p2.update();
        }

        self.update();

        if p1_turn {
            self.p1.update()
        } else {
            self.p2.update();
        }
    }
}

if每次我想更新当前播放器时,我都不想输入该语句。在我用过的其他语言中,我会写这样的东西:

struct Player {}

impl Player {
    fn update(&mut self) {}
}

struct GameBoard {
    p1: Player,
    p2: Player,
}

impl GameBoard {
    fn update(&mut self) {}
    fn update_current_player(&mut self, p1_turn: bool) {
        let p = if p1_turn { &mut self.p1 } else { &mut self.p2 };
        p.update();

        self.update();

        p.update();
    }
}

但这让借用检查器很恼火:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/lib.rs:18:9
   |
15 |         let p = if p1_turn { &mut self.p1 } else { &mut self.p2 };
   |                                                    ------------ first mutable borrow occurs here
...
18 |         self.update();
   |         ^^^^ second mutable borrow occurs here
19 | 
20 |         p.update();
   |         - first borrow later used here

必须有某种方法不必if每次都输入语句。我也不希望将if语句分解成一个函数p1_turn,因为写出函数调用仍然相当长。有人有建议吗?

我理解如果您在堆内Enum或堆上访问数据,为什么这种模式是不安全的,因为调用self.update()可能会使引用无效,但在这种情况下,引用不可能被任何代码无效,self.update()因为它只是引用到结构的一个字段。

标签: rustborrow-checker

解决方案


必须有某种方法不必if每次都输入语句。我也不希望将if语句分解成一个函数p1_turn,因为写出函数调用仍然相当长。

鉴于这些要求,您可以创建一个匿名闭包来捕获p1_turn变量并重新使用它。但是,为了避免重叠的可变借用,您必须将&mut self其作为参数传递给闭包。例子:

struct Player {}

impl Player {
    fn update(&mut self) {}
}

struct GameBoard {
    p1: Player,
    p2: Player,
}

impl GameBoard {
    fn update(&mut self) {}
    fn update_current_player(&mut self, p1_turn: bool) {
        let p_update = |gb: &mut GameBoard| {
            if p1_turn {
                gb.p1.update();
            } else {
                gb.p2.update();
            }
        };

        p_update(self);
        self.update();
        p_update(self);
    }
}

操场


推荐阅读