存储在结构中的闭包的生命周期
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 以允许它编译。)
我尝试将
在解释之前,先来一段代码:
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 以允许它编译。)