我正在try 计算合法的国际象棋棋棋步数,但在满足借来判断程序的要求时遇到了问题.我有一个实现这些方法的struct 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仍然在borrow 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

如何满足borrow 判断器的要求,以便代码可以编译?

推荐答案

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

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中是不允许的.

Rust相关问答推荐

if let声明中临时对象的生存期

即使参数和结果具有相同类型,fn的TypId也会不同

使用nom将任何空白、制表符、白线等序列替换为单个空白

程序退出后只写入指定管道的数据

如何在原始字符串中转义";#和#";

文档示例需要导入相关的 struct ,但仅在运行测试时.这是故意的行为吗?

在自身功能上实现类似移动的行为,以允许通过大小的所有者进行呼叫(&;mut;self)?

如何在Tauri中将变量从后端传递到前端

当T不执行Copy时,如何返回Arc Mutex T后面的值?

在rust sqlx中使用ilike和push bind

Rust函数的返回值不能引用局部变量或临时变量

随机函数不返回随机值

Rust 为什么被视为borrow ?

没有明确地说return会产生错误:match arms have incompatible types

为什么 `tokio::join!` 宏不需要 Rust 中的 `await` 关键字?

borrow 匹配手臂内部的可变

从嵌入式 Rust 中的某个时刻开始经过的时间

在 Rust 中,Weak 如何知道内部值何时被删除?

哪些特征通过 `Deref` 而哪些不通过?

Rust HRTB 是相同的,但编译器说一种类型比另一种更通用