【问题标题】:How can I modify self in a closure called from a member function?如何在从成员函数调用的闭包中修改 self ?
【发布时间】:2015-04-20 06:24:06
【问题描述】:

我正在尝试计算合法的国际象棋走法,但无法满足借用检查器的要求。我有一个实现这些方法的结构Chess(非重要代码替换为...):

// internal iterator over (possibly not legal) moves
fn get_moves<F>(&self, func: F)
where
    F: Fn(/* ... */),
{
    func(/* ... */); // move 1
    func(/* ... */); // move 2
    func(/* ... */); // etc...
}

fn is_legal_move(&mut self) -> bool {
    // notice this takes a mutable self. For performance
    // reasons, the move is made, legality is checked, then I
    // undo the move, so it must be mutable to be able to move pieces
    make_move(/* ... */);
    // check if legal
    undo_move(/* ... */);
    //return true if legal
}

fn get_legal_moves(&self) /* -> ... */ {
    self.get_moves(|/* ... */| {
        if self.is_legal_move(/* ... */) { // <-- error here
            // do something with legal move
        }
    })
}

我在get_legal_moves 中遇到编译错误,因为我在闭包内修改self,而get_moves 仍在借用self

我创建了一个简化示例来显示我要解决的问题:

struct Tester {
    x: i8,
}

impl Tester {
    fn traverse<Func>(&mut self, mut f: Func)
    where
        Func: FnMut(),
    {
        //in real-world, this would probably iterate over something
        f();
    }
}

fn main() {
    let mut tester = Tester { x: 8 };
    tester.traverse(|| {
        tester.x += 1; //I want to be able to modify tester here
    });
    println!("{}", tester.x);
}

Playground

错误:

error[E0499]: cannot borrow `tester` as mutable more than once at a time
  --> src/main.rs:17:5
   |
17 |       tester.traverse(|| {
   |       ^      -------- -- first mutable borrow occurs here
   |       |      |
   |  _____|      first borrow later used by call
   | |
18 | |         tester.x += 1; //I want to be able to modify tester here
   | |         ------ first borrow occurs due to use of `tester` in closure
19 | |     });
   | |______^ second mutable borrow occurs here

error[E0499]: cannot borrow `tester` as mutable more than once at a time
  --> src/main.rs:17:21
   |
17 |     tester.traverse(|| {
   |     ------ -------- ^^ second mutable borrow occurs here
   |     |      |
   |     |      first borrow later used by call
   |     first mutable borrow occurs here
18 |         tester.x += 1; //I want to be able to modify tester here
   |         ------ second borrow occurs due to use of `tester` in closure

我怎样才能满足借用检查器以便代码可以编译?

【问题讨论】:

  • 另一个建议:在本地克隆状态以进行移动。这就是我实现类似的方式
  • 另外,我真的不知道为什么这被否决了。这种行为开始在 [rust] 和 reddit 上惹恼我。
  • @sellibitze 最好的回答是投票选出您认为经过充分研究、措辞和切题的问题(所有符合how to ask a question 的问题)。不相信这个问题的人会投反对票。随着时间的推移,群众的智慧将决定^_^。

标签: rust closures borrow-checker mutability


【解决方案1】:

您可以做的最简单的更改是将引用传递给闭包:

struct Tester {
    x: i8,
}

impl Tester {
    fn traverse<F>(&mut self, mut f: F)
    where
        F: FnMut(&mut Tester),
    {
        f(self);
    }
}

fn main() {
    let mut tester = Tester { x: 8 };
    tester.traverse(|z| z.x += 1);
    println!("{}", tester.x);
}

这可以防止出现多个可变引用(也称为 aliasing),这在 Rust 中是不允许的。

【讨论】:

    猜你喜欢
    • 2018-07-20
    • 2021-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    相关资源
    最近更新 更多