Rust 锈蚀寿命混乱
我目前正在自学,并通过实施Tic-Tac-Toe进行练习 我有一个板结构(Rust 锈蚀寿命混乱,rust,rust-lifetimes,Rust,Rust Lifetimes,我目前正在自学,并通过实施Tic-Tac-Toe进行练习 我有一个板结构(单元格和游戏状态是简单的枚举,大小是3使用): 我正在尝试实现一种mark方法: impl Board { fn mark(&mut self, pos: &Position, player: Player) { // various checks omitted // mark cell for player self.cells[pos.row][
单元格
和游戏状态
是简单的枚举,大小
是3使用
):
我正在尝试实现一种mark
方法:
impl Board {
fn mark(&mut self, pos: &Position, player: Player) {
// various checks omitted
// mark cell for player
self.cells[pos.row][pos.col] = Cell::Filled(player);
// check whether player has won either via a full row or column (diagonals omitted):
if (0..SIZE).map(|i| &self.cells[pos.row][i]).all(|c| *c == Cell::Filled(player)) ||
(0..SIZE).map(|i| &self.cells[i][pos.col]).all(|c| *c == Cell::Filled(player)) {
self.state = GameState::Winner(player);
}
}
到目前为止还不错。。。但是有一个丑陋的代码重复
因此,我的下一步是引入闭包并用它替换if中的重复:
let all_in_line = |cell_access| (0..SIZE).map(cell_access).all(|c : &Cell| *c == Cell::Filled(player));
if all_in_line(|i : usize| &self.cells[pos.row][i]) ||
all_in_line(|i : usize| &self.cells[i][pos.col]) {
但这不起作用,因为它要求all_in_line
是泛型的(因为我传递给它的两个闭包具有不同的匿名类型),所以我的下一步是执行类似于类型擦除的操作:
fn mark(&mut self, pos: &Position, player: Player) {
let all_in_line = |cell_access : Box<dyn Fn(usize) -> &Cell>| (0..SIZE).map(cell_access).all(|c : &Cell| *c == Cell::Filled(player));
if all_in_line(Box::new(|i : usize| &self.cells[pos.row][i])) ||
all_in_line(Box::new(|i : usize| &self.cells[i][pos.col])) {
self.state = GameState::Winner(player);
}
我已尝试将mark
修改为fn mark
,但失败:
error[E0597]: `self` does not live long enough
fn mark<'a>(&'a mut self, pos: &Position, player: Player) {
-- lifetime `'a` defined here
...
if all_in_line(Box::new(|i : usize| &self.cells[pos.row][i]))
----------- -^^^^------------------
| ||
| |borrowed value does not live long enough
| returning this value requires that `self` is borrowed for `'a`
value captured here
...
}
- `self` dropped here while still borrowed
错误[E0597]:'self'活得不够长
fn标记
但现在rust编译器抱怨在cell_access的类型说明符中缺少返回引用的生存期参数:
据我所知,这里的问题是为了能够以这种形式编写代码,cell\u access
函数的签名需要引用其有效的生存期,这是不可能的,因为这个生命周期没有名字——它是在闭包创建过程中隐含的self
的本地重传。您尝试使用&'a mut self
是无效的,因为它没有捕捉到闭包的self
是函数的self
的重新编译,因此不需要完全相同的生存期,因为可变借用的生存期是不变的,而不是协变的;它们不能任意地缩短(因为这将打破可变引用的排他性)
最后一点让我想到了如何解决这个问题:将all\u-in\u-line
代码移动到一个函数中,该函数通过不可变引用获取self
。这包括:
impl板{
马克布尔{
让所有单元格都进入:框和单元格>|{
(0.尺寸)
.map(单元访问)
.all(|c:&Cell |*c==Cell::Filled(player))
};
所有输入行(框::新建(| i:usize |和self.cells[pos.row][i]))
||所有输入行(框::新建(| i:usize |和self.cells[i][pos.col]))
}
}
然而,虽然上述方法确实有效,但我认为最好的选择是,不要试图将all_in_line
作为一个闭包,而是将其作为一个单独的函数(可以是通用的),并完全避免使用Box
在这个位置上,我们可以写出实际需要的生存期-函数的生存期generic
但现在rust编译器抱怨在cell_access的类型说明符中缺少返回引用的生存期参数:
据我所知,这里的问题是为了能够以这种形式编写代码,cell\u access
函数的签名需要引用其有效的生存期,这是不可能的,因为这个生命周期没有名字——它是在闭包创建过程中隐含的self
的本地重传。您尝试使用&'a mut self
是无效的,因为它没有捕捉到闭包的self
是函数的self
的重新编译,因此不需要完全相同的生存期,因为可变借用的生存期是不变的,而不是协变的;它们不能任意地缩短(因为这将打破可变引用的排他性)
最后一点让我想到了如何解决这个问题:将all\u-in\u-line
代码移动到一个函数中,该函数通过不可变引用获取self
。这包括:
impl板{
马克布尔{
让所有单元格都进入:框和单元格>|{
(0.尺寸)
.map(单元访问)
.all(|c:&Cell |*c==Cell::Filled(player))
};
所有输入行(框::新建(| i:usize |和self.cells[pos.row][i]))
||所有输入行(框::新建(| i:usize |和self.cells[i][pos.col]))
}
}
然而,虽然上述方法确实有效,但我认为最好的选择是,不要试图将all_in_line
作为一个闭包,而是将其作为一个单独的函数(可以是通用的),并完全避免使用Box
在这个位置上,我们可以写出我们实际需要的生存期-函数的生存期generic注意,为了避免污染全局名称空间,all_In_line
函数可以在mark
()中定义。是的,这绝对是一种合理的修复方法。我仍然很想了解我的代码到底有什么问题(以及为什么显式函数没有像我的代码那样存在生命周期问题…@AndreasMorhammer我补充了一些想法。我不太善于思考这一点,因此无法给出“这不可行,因为……如果我们试图使语言与众不同,那么其他事情就会中断……”的总体图景。但我希望这能有所帮助。非常感谢,这非常有帮助!请注意,为了避免污染全局名称空间,可以在mark
()中定义all_in_line
函数。是的,这绝对是一种合理的修复方法。我仍然很想了解我的代码到底有什么问题(以及为什么显式函数没有像我的代码那样存在生命周期问题…@AndreasMorhammer我补充了一些想法。我不太善于思考这一点,因此无法给出“这不可行,因为……如果我们试图使语言与众不同,那么其他事情就会中断……”的总体图景。但我希望这能有所帮助。非常感谢,这非常有帮助!
error[E0106]: missing lifetime specifier
let all_in_line = |cell_access : Box<dyn Fn(usize) -> &Cell>| (0..SIZE).map(cell_access).all(|c : &Cell| *c == Cell::Filled(player));
^ expected named lifetime parameter
error[E0597]: `self` does not live long enough
fn mark<'a>(&'a mut self, pos: &Position, player: Player) {
-- lifetime `'a` defined here
...
if all_in_line(Box::new(|i : usize| &self.cells[pos.row][i]))
----------- -^^^^------------------
| ||
| |borrowed value does not live long enough
| returning this value requires that `self` is borrowed for `'a`
value captured here
...
}
- `self` dropped here while still borrowed