Rust基于lambda的迭代器生命周期标注问题求解
报错根因
你遇到的编译错误本质是构造了自引用结构:
- 你将
text的所有权移动进了from_fn的闭包中,同时又在闭包的持久状态chunk里存储了指向这个text的切片引用。 - Rust的安全规则不允许普通的自引用结构存在:闭包本身是可以被移动的,一旦闭包发生移动,内部存储的
text的内存地址会改变,chunk里存的切片就会变成悬空指针,这是Rust禁止的未定义行为。 - 这种情况无法通过添加生命周期标注解决:Rust的生命周期系统本身就没有能力描述自引用结构的生命周期约束,不是编译器推导能力的问题。
最优解决方案
你的场景完全可以避免构造自引用结构,既然每次需要切片时都是从text从头取到指定索引,只需要把原来存储切片的chunk替换为存储索引即可,用到切片时临时从text生成,用完就丢弃,不需要持久保存引用:
use std::iter; fn example(text: String) -> impl Iterator<Item = Option<String>> { let mut i = 0; // 用存储上一次的索引代替存储切片,避免自引用 let mut prev_end = None; iter::from_fn(move || { if i <= text.len() { // 用到切片时临时生成,不需要持久保存 let p_chunk = prev_end.map(|end| String::from(&text[..end])); prev_end = Some(i); i += 1; Some(p_chunk) } else { None } }) } fn main() {}
这个方案没有任何额外性能开销,完全符合你的预期逻辑,也不需要引入任何第三方库,是当前Rust版本下最简便的实现方式。
如果你的实际业务场景比最小复现代码复杂,必须要持久存储指向闭包内部自有数据的引用,可以考虑使用Pin固定堆内存或者ouroboros这类自引用结构库来实现,但对于你当前的场景完全不需要用到这么重的方案。
内容的提问来源于stack exchange,提问作者Andrei
相关产品推荐
相关产品推荐

