我遇到了一个简化为以下问题的问题:
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
我们的想法是,迭代器会在其字段中反映一系列工作,并且在每一步中,它都会向调用代码生成一个引用 . 在这种情况下,我可以将其建模为产生状态的副本而不是参考,但让我们假装不可能或者只是不方便的昂贵 .
直觉上这不应该是一个问题,因为借用检查器可以确保状态,但是 Iterator
特性不会通过借用检查器获得任何东西 .
我阅读了“Iterators yielding mutable references”博文章,但我涉及可变引用 .
1 回答
这是不可能的 . 如果允许,可以再次调用
next
,从而修改通过&
也可见的数据,甚至完全使参考无效 . 这是因为self
对象本身与返回的引用之间没有连接:没有明确的生命周期链接它们 .对于编译器推理这个并允许将引用返回
self
next需要签名之类的但是,这与特征的签名不同,特征的签名不允许作为通用代码,只需要
T: Iterator<...>
无法判断对某些T
的返回值的使用有不同的要求;所有都必须以相同的方式处理 .Iterator
trait设计用于独立于迭代器对象的返回值,这对于像.collect
这样的迭代器适配器来说是正确和安全的 . 这对于许多用途(例如在for
循环内的瞬态使用)来说比限制性更具限制性,但它恰好是目前的情况 . 我认为我们现在没有正确推广这种特性/ for循环的工具(具体来说,我认为我们需要具有更高等级生命周期的相关类型),但可能在未来 .