我有一个迭代器trait,它使用泛型关联类型来允许返回值引用迭代器拥有的数据:
pub trait MyIterator {
type T<'a>
where
Self: 'a;
fn next<'b>(&'b mut self) -> Option<Self::T<'b>>;
}
一个示例实现如下:
struct FooIterator<'counter> {
data: Vec<String>,
counter: &'counter AtomicU32,
index: usize
}
impl<'counter> MyIterator for FooIterator<'counter> {
type T<'d> = &'d str
where
Self: 'd;
fn next<'e>(&'e mut self) -> Option<Self::T<'e>> {
self.counter.fetch_add(1, Ordering::SeqCst);
self.index += 1;
Some(&self.data[self.index])
}
}
现在,我想有一个返回impl MyIterator
对象而不使实现类型公开的工厂。然而,我不知道如何写生命周期。
我的第一次尝试是:
struct Factory {
data: Vec<String>,
counter: AtomicU32,
}
impl Factory {
fn new() -> Self {
Factory {
data: vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()],
counter: AtomicU32::new(0),
}
}
fn create<'f>(&'f self) -> impl MyIterator<T<'_> = &'_ str> {
FooIterator {
data: self.data.clone(),
counter: &self.counter,
index: 0
}
}
}
但是,当尝试使用返回的迭代器时,会导致双重借用错误,如下所示:https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=6490de8f21539537764d8f628454c5c1
接下来,我尝试使用更高级别的Trait边界,这似乎应该工作,但我不能得到以下编译,因为似乎'g
不在where子句的范围内(https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=beb46184de6f96bf83b64e838da4a335):
fn create<'f>(&'f self) -> impl for<'g> MyIterator<T<'g> = &'g str> + 'f where 'f: 'g {
FooIterator {
data: self.data.clone(),
counter: &self.counter,
index: 0
}
}
没有返回impl MyIterator
代码工作正常,但我不想暴露FooIterator
类型。看这个游乐场:https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=2c595c136077791a692ea6e0a41c057c
你的问题在于MyIterator
的定义,因为在那里next
函数接受一个可变的借用到self,并返回一些与该可变借用一样存在的东西,这不是你期望从迭代器中得到的。
这是微妙的,因为它不会使代码不健全,它只是强制执行过多的约束,这反过来又使得不可能在不出错的情况下使用该特性。对MyIterator
特性的生命周期进行了简单的重构,使其能够工作。看操场