为LazyList实现FromIterator时生命周期约束更严格报错如何解决?
问题根因
Rust标准库的FromIterator trait定义中,from_iter方法的泛型参数I没有任何生命周期约束,你在实现时额外增加了I: 'a的要求,违反了trait的契约,因此抛出E0276错误。
你额外加这个约束的根源是现有Lazy、LazyList的设计要求闭包必须满足'a生命周期,而惰性构建列表需要把迭代器捕获到闭包里,所以不得不给I加'a约束,最终和trait定义冲突。
可行解决方案
方案1:修改from_iter为立即求值构建,改动最小
该方案不需要调整现有Lazy/LazyList的生命周期设计,仅修改FromIterator的实现即可,唯一的缺点是from_iter会立即迭代所有元素,失去惰性构建的特性:
impl<'a, T: 'a + Clone> FromIterator<T> for LazyList<'a, T> { fn from_iter<I: IntoIterator<Item = T>>(itrbl: I) -> LazyList<'a, T> { let mut list = Empty; // 先收集所有元素再倒序构建列表,避免递归开销 let items: Vec<T> = itrbl.into_iter().collect(); for item in items.into_iter().rev() { list = Cons(item, Rc::new(Lazy::evaluated(list))); } list } }
方案2:移除Lazy/LazyList的生命周期绑定,保留惰性构建特性
如果你需要保留from_iter的惰性构建能力,可以把Lazy里的闭包约束从'a改成'static,同时删除所有相关的生命周期标注:
- 先调整
lazy模块,移除生命周期参数:
pub mod lazy { use crate::thunk::Invoke; use std::cell::UnsafeCell; use std::mem::replace; use std::ops::Deref; pub struct Lazy<T>(UnsafeCell<LazyState<T>>); enum LazyState<T> { Unevaluated(Box<dyn Invoke<T> + 'static>), EvaluationInProgress, Evaluated(T), } use self::LazyState::*; impl<T> Lazy<T> { #[inline] pub fn new<F: 'static + FnOnce() -> T>(func: F) -> Lazy<T> { Lazy(UnsafeCell::new(Unevaluated(Box::new(func)))) } #[inline] pub fn evaluated(val: T) -> Lazy<T> { Lazy(UnsafeCell::new(Evaluated(val))) } #[inline(always)] fn force(&self) { unsafe { match *self.0.get() { Evaluated(_) => {}, EvaluationInProgress => panic!("Lazy::force called recursively!!!"), _ => { let ue = replace(&mut *self.0.get(), EvaluationInProgress); if let Unevaluated(thnk) = ue { *self.0.get() = Evaluated(thnk.invoke()); } } } } } #[inline] pub fn unwrap(self) -> T { self.force(); match self.0.into_inner() { Evaluated(v) => v, _ => unreachable!() } } } impl<T> Deref for Lazy<T> { type Target = T; #[inline] fn deref(&self) -> &T { self.force(); match *unsafe { &*self.0.get() } { Evaluated(ref v) => v, _ => unreachable!(), } } } }
- 再调整
lazylist模块,删除所有生命周期'a的标注,把cons方法的闭包约束改为'static,原有FromIterator实现删除+ 'a约束即可编译通过。
注意:该方案要求所有捕获到Lazy闭包里的变量都满足'static生命周期,不适合需要捕获栈引用的场景。
内容的提问来源于stack exchange,提问作者hkBst
相关产品推荐
相关产品推荐

