方法返回具有相同生存期的结构迭代器的生存期 [英] Lifetimes for method returning iterator of structs with same lifetime

查看:84
本文介绍了方法返回具有相同生存期的结构迭代器的生存期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设以下人为设计的示例:

Assume the following contrived example:

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,
            })
    }
}

这不能编译,因为据我了解,在lambda中创建的点的生命周期是不正确的:

This doesn't compile because from what I understand the lifetime of the points created in the lambda isn't correct:

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>> {
   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

尽管如此,我还是有些茫然,因为看起来这里的生命周期很有意义. Point的生存期是由对Board的引用的生存期引起的.因此,Point<'a>引用寿命为'a的板,因此它应该能够创建更多的Point<'a>,因为它们的板引用将具有相同的寿命('a).

I'm a bit lost as to why this is the case though, because it seems like the lifetimes here make sense. A Point's lifetime is caused by the lifetime of the reference to the Board. Thus, a Point<'a> has a reference to a board with lifetime 'a so it should be able to create more Point<'a>s because their board references will have the same lifetime ('a).

但是,如果我删除了lambda,它将起作用:

But, if I remove the lambda, it works:

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},
        ]
    }
}

因此,我怀疑问题在于这样的事实,即lambda可能会在生命周期'a结束后运行.但是,这是否意味着我不能懒惰地产生这些点?

So, I suspect the problem lies in the fact that the lambda may be run after the lifetime 'a ends. But, does this mean that I can't lazily produce these points?

tl; dr如何通过一种懒惰地创建新结构的方法使借阅检查器满意,该结构的生命周期与创建它们的结构相关联?

tl;dr How do I make the borrow checker happy with a method that lazily creates new structs whose lifetimes are tied to the struct creating them?

推荐答案

当方法中存在此类问题时,要做的一件好事就是为&self添加明确的生存期:

When you have this kind of issue in a method, a good thing to do is to add an explicit lifetime to &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,
        })
}

现在的错误更好了

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 {
   |                         ^^^^^^^^^^^^^^^

然后,您只需要按照编译器的建议添加move关键字,即可告诉您不再使用&'a self.

You then just need to add the move keyword as advised by the compiler, to say to it that you will not use &'a self again.

请注意,self的生存期不必与Point的生存期相同.最好使用以下签名:

Note that the lifetime of self has not to be the same as the lifetime of Point. This is better to use this signature:

fn neighbors<'b>(&'b self) -> impl 'b + Iterator<Item = Point<'a>>

这篇关于方法返回具有相同生存期的结构迭代器的生存期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆