借用检查器阻止迭代器在递归函数内调用 for_each
Borrow checker stops iterator from calling for_each inside a recursive function
我正在用 Rust 和 WASM 制作扫雷副本。目前,我正在完成 Mine Sweeper 的逻辑。主要是,当用户点击一个附近没有炸弹的空方块时,程序会搜索邻居并显示那些附近没有炸弹的方块。
请注意自动打开的游戏中的大片空白区域。
该程序使用两个一维向量来存储炸弹的位置以及每个图块的状态。
然后这个递归程序将找到的空瓦片的状态设置为 SpotState::Empty,然后与邻居继续此操作。
/// for uncovering empty neighbors and recursively uncovering their empty neighbors
fn uncover_empty_neighbors(&mut self, col: usize, row: usize) {
// break case for recursion
if self.state_vec[self.get_idx(col, row)] == SpotState::Empty {
return;
}
if self.get_mine_neighbor_count(col, row) == 0 {
let idx = self.get_idx(col, row);
self.state_vec[idx] = SpotState::Empty;
}
let inbound_neighbors = POSSIBLE_NEIGHBORS
.iter()
.map(|[x, y]| [x + col as isize, y + row as isize])
.filter(|[x, y]| self.check_bounds(x, y))
.for_each(|[x, y]| self.uncover_empty_neighbors(x as usize, y as usize));
}
但是,我得到这个错误:
error[E0500]: closure requires unique access to `*self` but it is already borrowed
--> src\lib.rs:138:23
|
137 | .filter(|[x, y]| self.check_bounds(x, y))
| -------- ---- first borrow occurs due to use of `*self` in closure
| |
| borrow occurs here
138 | .for_each(|[x, y]| {
| -------- ^^^^^^^^ closure construction occurs here
| |
| first borrow later used by call
139 | self.uncover_empty_neighbors(x as usize, y as usize)
| ---- second borrow occurs due to use of `*self` in closure
For more information about this error, try `rustc --explain E0500`.
error: could not compile `minesweeper_wasm` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed
我对如何实现这一点感到困惑。闭包是否无法捕获 self
因为 self
已经在函数 uncover_empty_neighbors()
中可变地借用了?在这种情况下使用 self
是否不可避免地是一个糟糕的举动,还有什么其他数据结构会有用?
你只需要尽可能避免借钱。在这种情况下,考虑到它们是 usize
,即 Copy
:
,制作一个采用拥有的 width/height
的免费方法就足够了
/// for checking the bounds of a given row and col since neighbors are blindly checked.
fn check_bounds(col: &isize, row: &isize, width: usize, height: usize) -> bool {
if col < &0 || row < &0 || col >= &(width as isize) || row >= &(height as isize) {
return false;
}
true
}
/// for uncovering empty neighbors
fn uncover_empty_neighbors(&mut self, col: usize, row: usize) {
// break case for recursion
if self.state_vec[self.get_idx(col, row)] == SpotState::Empty {
return;
}
if self.get_mine_neighbor_count(col, row) == 0 {
let idx = self.get_idx(col, row);
self.state_vec[idx] = SpotState::Empty;
}
let (width, height) = (self.width, self.height);
let inbound_neighbors = POSSIBLE_NEIGHBORS
.iter()
.map(|[x, y]| [x + col as isize, y + row as isize])
.filter(|[x, y]| Self::check_bounds(x, y, width, height))
.for_each(|[x, y]| {
self.uncover_empty_neighbors(x.clone() as usize, y.clone() as usize)
});
}
这是怎么回事?好吧,您正在使用迭代器使用的闭包捕获 self
,因为迭代器是惰性的,因此 borrow
在您收集之前不会释放(或者在您的情况下整个 for_each
被评估)。
是的。请记住,迭代器是延迟计算的,因此传递给 filter
的闭包需要借用 self
并且 在 for_each
执行时继续借用它 ,因为 for_each
需要评估调用它的迭代器。
您可以尝试重组代码,使任何一种方法都不依赖于 self
,或者您可以简单地 collect()
到 Vec
之后的新 Vec
17=],因此在 uncover_empty_neighbors
执行时没有不可变借用。
我正在用 Rust 和 WASM 制作扫雷副本。目前,我正在完成 Mine Sweeper 的逻辑。主要是,当用户点击一个附近没有炸弹的空方块时,程序会搜索邻居并显示那些附近没有炸弹的方块。
请注意自动打开的游戏中的大片空白区域。
该程序使用两个一维向量来存储炸弹的位置以及每个图块的状态。
然后这个递归程序将找到的空瓦片的状态设置为 SpotState::Empty,然后与邻居继续此操作。
/// for uncovering empty neighbors and recursively uncovering their empty neighbors
fn uncover_empty_neighbors(&mut self, col: usize, row: usize) {
// break case for recursion
if self.state_vec[self.get_idx(col, row)] == SpotState::Empty {
return;
}
if self.get_mine_neighbor_count(col, row) == 0 {
let idx = self.get_idx(col, row);
self.state_vec[idx] = SpotState::Empty;
}
let inbound_neighbors = POSSIBLE_NEIGHBORS
.iter()
.map(|[x, y]| [x + col as isize, y + row as isize])
.filter(|[x, y]| self.check_bounds(x, y))
.for_each(|[x, y]| self.uncover_empty_neighbors(x as usize, y as usize));
}
但是,我得到这个错误:
error[E0500]: closure requires unique access to `*self` but it is already borrowed
--> src\lib.rs:138:23
|
137 | .filter(|[x, y]| self.check_bounds(x, y))
| -------- ---- first borrow occurs due to use of `*self` in closure
| |
| borrow occurs here
138 | .for_each(|[x, y]| {
| -------- ^^^^^^^^ closure construction occurs here
| |
| first borrow later used by call
139 | self.uncover_empty_neighbors(x as usize, y as usize)
| ---- second borrow occurs due to use of `*self` in closure
For more information about this error, try `rustc --explain E0500`.
error: could not compile `minesweeper_wasm` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed
我对如何实现这一点感到困惑。闭包是否无法捕获 self
因为 self
已经在函数 uncover_empty_neighbors()
中可变地借用了?在这种情况下使用 self
是否不可避免地是一个糟糕的举动,还有什么其他数据结构会有用?
你只需要尽可能避免借钱。在这种情况下,考虑到它们是 usize
,即 Copy
:
width/height
的免费方法就足够了
/// for checking the bounds of a given row and col since neighbors are blindly checked.
fn check_bounds(col: &isize, row: &isize, width: usize, height: usize) -> bool {
if col < &0 || row < &0 || col >= &(width as isize) || row >= &(height as isize) {
return false;
}
true
}
/// for uncovering empty neighbors
fn uncover_empty_neighbors(&mut self, col: usize, row: usize) {
// break case for recursion
if self.state_vec[self.get_idx(col, row)] == SpotState::Empty {
return;
}
if self.get_mine_neighbor_count(col, row) == 0 {
let idx = self.get_idx(col, row);
self.state_vec[idx] = SpotState::Empty;
}
let (width, height) = (self.width, self.height);
let inbound_neighbors = POSSIBLE_NEIGHBORS
.iter()
.map(|[x, y]| [x + col as isize, y + row as isize])
.filter(|[x, y]| Self::check_bounds(x, y, width, height))
.for_each(|[x, y]| {
self.uncover_empty_neighbors(x.clone() as usize, y.clone() as usize)
});
}
这是怎么回事?好吧,您正在使用迭代器使用的闭包捕获 self
,因为迭代器是惰性的,因此 borrow
在您收集之前不会释放(或者在您的情况下整个 for_each
被评估)。
是的。请记住,迭代器是延迟计算的,因此传递给 filter
的闭包需要借用 self
并且 在 for_each
执行时继续借用它 ,因为 for_each
需要评估调用它的迭代器。
您可以尝试重组代码,使任何一种方法都不依赖于 self
,或者您可以简单地 collect()
到 Vec
之后的新 Vec
17=],因此在 uncover_empty_neighbors
执行时没有不可变借用。