我遇到了一个简化为以下问题的问题:
struct MyIter {
vec: Vec<i8>,
}
fn fill_with_useful_data(v: &mut Vec<i8>) {
/* ... */
}
impl<'a> Iterator for MyIter {
type Item = &'a [i8];
fn next(&mut self) -> Option<&'a [i8]> {
fill_with_useful_data(&mut self.vec);
Some(&self.vec)
}
}
fn main() {
for slice in (MyIter { vec: Vec::new() }) {
println!("{}", slice);
}
}
这会产生错误:
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:9:6
|
9 | impl<'a> Iterator for MyIter {
| ^^ unconstrained lifetime parameter
这个想法是迭代器做了很多反映在它的字段中的工作,并且在每一步中,它产生了对调用代码的引用。在这种情况下,我可以将其建模为产生状态的副本而不是参考,但让我们假装不可能或者只是不方便的昂贵。
直观地说这应该不是问题,因为借用检查器可以确保不再调用.next()
,而仍然可以使用所产生的引用来检查迭代器的状态,但是Iterator
特征似乎没有直接提供那种东西。即使有一些排列,例如只是在迭代器本身中持有对向量的引用,或者使迭代器成为引用或某些东西,以便将生命周期加入到先前类型中,我无法通过借用检查器获得任何东西。
我阅读了“Iterators yielding mutable references”博文,但我不确定它是否适用于我的问题/不涉及可变引用的问题。
答案 0 :(得分:11)
这是不可能的。如果允许,可以再次调用next
,从而修改通过&
也可见的数据,甚至完全使参考无效。这是因为self
对象本身与返回的引用之间没有任何关联:没有明确的生命周期链接它们。
为了让编译器对此进行推理并允许将引用返回self
,接下来需要签名
fn next(&'a mut self) -> Option<&'a [i8]>
然而,这与特征的签名不同,特征的签名不允许作为通用代码只需要T: Iterator<...>
无法判断对某些T
的返回值的使用有不同的要求;所有这些都必须以同样的方式处理。
Iterator
特征是为独立于迭代器对象的返回值而设计的,这对于像.collect
这样的迭代器适配器来说是正确和安全的。这对于许多用途(例如for
循环内的瞬态使用)来说比限制性更具限制性,但它正是它现在的样子。我不认为我们现在有适当推广这种特性/ for循环的工具(具体来说,我认为我们需要具有更高等级生命周期的相关类型),但可能在未来。