Rust结构体存储闭包时的生命周期标注报错解决
问题根因
你写的Box<dyn Fn(Coord) -> bool>默认带有*'static生命周期约束*,这也是编译器提示你给泛型P加'static bound的原因。但你的闭包捕获了Board实例的引用,根本不可能满足'static要求,核心问题是没有给结构体和闭包绑定匹配的自定义生命周期,导致编译器默认用最严格的静态生命周期检查。
实现步骤
只需要给相关代码加上对应生命周期标注即可,不需要修改核心逻辑:
- 给
SquareIterator添加生命周期参数,将闭包trait对象的生命周期绑定到该参数type Coord = (usize, usize); pub struct SquareIterator<'a> { upper_bounds: Coord, direction: Coord, // 移除默认'static约束,绑定到生命周期'a predicate: Box<dyn Fn(Coord) -> bool + 'a>, current: Coord, } - 修改
new方法的签名,给泛型P添加匹配的生命周期约束,返回带生命周期标注的迭代器实例impl<'a> SquareIterator<'a> { pub fn new<P>( start_square: Coord, direction: Coord, board_size: Coord, predicate: P, ) -> SquareIterator<'a> where P: Fn(Coord) -> bool + 'a, { SquareIterator { upper_bounds: board_size, direction, predicate: Box::new(predicate), current: start_square, } } } - 为Iterator实现添加对应生命周期标注,迭代逻辑不需要改动
impl<'a> Iterator for SquareIterator<'a> { 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 } } } - 业务调用处给返回值添加隐式生命周期标注,让闭包捕获的
&self生命周期和迭代器自动对齐struct Board { squares: Vec<Vec<u8>>, // 其他原有成员 } 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 }) } // 原有实现的board_size方法 fn board_size(&self) -> Coord { (self.squares[0].len(), self.squares.len()) } }
原理说明
- Rust中所有
trait对象如果不手动指定生命周期,编译器会默认要求其内部捕获的所有引用满足'static生命周期,这也是最初报错的直接原因 - 自定义生命周期
'a相当于和编译器约定:闭包中捕获的所有引用,存活时间不会短于迭代器实例本身,从根源上避免悬垂引用 - 调用处用
'_隐式生命周期标注,会自动将返回的迭代器生命周期和&self的借用周期绑定:只要迭代器还在使用,Board的借用就一直有效,完全符合Rust借用检查规则,不会出现内存安全问题。
内容的提问来源于stack exchange,提问作者BitTickler
相关产品推荐
相关产品推荐

