Bai*_*ker 3 lifetime rust borrow-checker
假设以下人为的例子:
struct Board {
squares: Vec<i32>,
}
struct Point<'a> {
board: &'a Board,
x: i32,
y: i32,
}
impl<'a> Point<'a> {
pub fn neighbors(&self) -> impl Iterator<Item = Point<'a>> {
[(0, -1), (-1, 0), (1, 0), (1, 0)]
.iter().map(|(dx, dy)| Point {
board: self.board,
x: self.x + dx,
y: self.y + dy,
})
}
}
Run Code Online (Sandbox Code Playgroud)
这不能编译,因为根据我的理解,在lambda中创建的点的生命周期是不正确的:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:14:25
|
14 | .iter().map(|(dx, dy)| Point {
| _________________________^
15 | | board: self.board,
16 | | x: self.x + dx,
17 | | y: self.y + dy,
18 | | })
| |_____________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 12:5...
--> src/main.rs:12:5
|
12 | / pub fn neighbors(&self) -> impl Iterator<Item = Point<'a>> {
13 | | [(0, -1), (-1, 0), (1, 0), (1, 0)]
14 | | .iter().map(|(dx, dy)| Point {
15 | | board: self.board,
... |
18 | | })
19 | | }
| |_____^
= note: ...so that the types are compatible:
expected &&Point<'_>
found &&Point<'a>
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 11:1...
--> src/main.rs:11:1
|
11 | impl<'a> Point<'a> {
| ^^^^^^^^^^^^^^^^^^
note: ...so that return value is valid for the call
--> src/main.rs:12:32
|
12 | pub fn neighbors(&self) -> impl Iterator<Item = Point<'a>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
我有点迷失为什么会出现这种情况,因为看起来这里的生命有意义.甲Point的生存期由参照的寿命造成的Board.因此,a Point<'a>具有对具有生命周期的板的引用,'a因此它应该能够创建更多的Point<'a>s,因为它们的板引用将具有相同的寿命('a).
但是,如果我删除lambda,它的工作原理是:
impl<'a> Point<'a> {
pub fn neighbors(&self) -> [Point<'a>; 4] {
[
Point { board: self.board, x: self.x , y: self.y - 1},
Point { board: self.board, x: self.x - 1, y: self.y },
Point { board: self.board, x: self.x + 1, y: self.y },
Point { board: self.board, x: self.x , y: self.y + 1},
]
}
}
Run Code Online (Sandbox Code Playgroud)
因此,我怀疑问题在于lambda可能在生命周期'a结束后运行.但是,这是否意味着我不能懒洋洋地产生这些观点?
tl; dr如何让借用检查器满足于一种懒惰地创建新结构的方法,这些结构的生命周期与创建它们的结构相关联?
当您在方法中遇到此类问题时,最好的做法是将显式生存期添加到&self:
pub fn neighbors(&'a self) -> impl Iterator<Item = Point<'a>> {
[(0, -1), (-1, 0), (1, 0), (1, 0)]
.iter().map(|(dx, dy)| Point {
board: self.board,
x: self.x + dx,
y: self.y + dy,
})
}
Run Code Online (Sandbox Code Playgroud)
错误现在更好
error[E0373]: closure may outlive the current function, but it borrows `self`, which is owned by the current function
--> src/main.rs:14:30
|
14 | .iter().map(|(dx, dy)| Point {
| ^^^^^^^^^^ may outlive borrowed value `self`
15 | board: self.board,
| ---- `self` is borrowed here
help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword
|
14 | .iter().map(move |(dx, dy)| Point {
| ^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
然后,您只需要move根据编译器的建议添加关键字,并告诉它您不会&'a self再次使用.
请注意,生命周期self不得与生命周期相同Point.最好使用此签名:
fn neighbors<'b>(&'b self) -> impl 'b + Iterator<Item = Point<'a>>
Run Code Online (Sandbox Code Playgroud)