存储在结构中的闭包的生命周期

Lifetime of a closure stored in a struct

我尝试将 的答案应用到我的情况中,但没有成功。 我想,我尝试做的要简单得多。

在解释之前,先来一段代码:

type Coord = (usize, usize);

pub struct SquareIterator {
    upper_bounds: Coord,
    direction: Coord,
    predicate: Box<dyn Fn(Coord) -> bool>,
    current: Coord,
}

impl SquareIterator {
    pub fn new<P>(
        start_square: Coord,
        direction: Coord,
        board_size: Coord,
        predicate: P,
    ) -> SquareIterator
    where
        P: Fn(Coord) -> bool,
    {
        SquareIterator {
            upper_bounds: board_size,
            direction,
            predicate: Box::new(predicate),
            current: start_square,
        }
    }
}

impl Iterator for SquareIterator {
    type Item = Coord;

    fn next(&mut self) -> Option<Self::Item> {
        let next = (
            self.current.0 + self.direction.0,
            self.current.1 + self.direction.1,
        );
        if next.0 >= self.upper_bounds.0 || next.1 >= self.upper_bounds.1 {
            None
        } else if (self.predicate)(next) {
            self.current = next;
            Some(self.current)
        } else {
            None
        }
    }
}

它是关于谓词闭包的,它应该与包含结构 SquareIterator 存在的时间一样长。

应用程序代码,使用它看起来大致如下:

struct Board {
    // ... some members ...
}
impl Board {
    pub fn queen_moves(&self, queen_coord: (u8, Coord)) -> SquareIterator {
        SquareIterator::new(queen_coord.1, (0, 1), self.board_size(), |coord| {
            self.squares[coord.1][coord.0] == sv::EMPTY
        })
    }
}

折腾了两个小时,把rust book的lifetimes chapter看了两遍,看了上面提到的其他Whosebug的问题,还是一头雾水,不知道怎么教Rust,我的闭包只要迭代器还活着...

虽然我知道,缺少生命周期的东西,但当前的 ccode 产生了错误:

> error[E0310]: the parameter type `P` may not live long enough
  --> amazons-engine/src/lib.rs:33:18
   |
33 |       predicate: Box::new(predicate),
   |                  ^^^^^^^^^^^^^^^^^^^ ...so that the type `P` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound...
   |
29 |     P: Fn(Coord) -> bool + 'static, {
   |                          +++++++++

For more information about this error, try `rustc --explain E0310`.

那么,怎么做呢?

您需要告诉编译器 SquareIterator 可能绑定到特定的生命周期。从它们的环境中借用的闭包不是 'static,但是没有生命周期参数的结构被假定为不引用任何内容(例如 'static)本身。这会使你借用 self 的闭包与 implied-static 生命周期不兼容。

第一步是告诉编译器SquareIterator可能引用了一个外部生命周期,这个生命周期属于闭包类型:

pub struct SquareIterator<'a> {
    upper_bounds: Coord,
    direction: Coord,
    predicate: Box<dyn 'a + Fn(Coord) -> bool>,
    current: Coord,
}

第二步是类似地调整构造函数,它将提供的闭包的生命周期与返回的 SquareIterator 的生命周期绑定在一起,允许编译器为您推断 'a:

impl SquareIterator<'_> {
    pub fn new<'a, P>(
        start_square: Coord,
        direction: Coord,
        board_size: Coord,
        predicate: P,
    ) -> SquareIterator<'a>
    where
        P: 'a + Fn(Coord) -> bool,
    { ... }
}

最后,impl Iterator 块需要包含生命周期,但我们可以使用“请推断我”生命周期 '_ 因为实现不依赖于它:

impl Iterator for SquareIterator<'_> { ... }

(Playground,它有一些占位符 types/methods 以允许它编译。)