Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 锈蚀寿命混乱_Rust_Rust Lifetimes - Fatal编程技术网

Rust 锈蚀寿命混乱

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][

我目前正在自学,并通过实施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][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