我可以编写一个自我变异的迭代器,然后产生一个引用吗?

时间:2014-09-06 17:28:10

标签: rust

我遇到了一个简化为以下问题的问题:

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”博文,但我不确定它是否适用于我的问题/不涉及可变引用的问题。

1 个答案:

答案 0 :(得分:11)

这是不可能的。如果允许,可以再次调用next,从而修改通过&也可见的数据,甚至完全使参考无效。这是因为self对象本身与返回的引用之间没有任何关联:没有明确的生命周期链接它们。

为了让编译器对此进行推理并允许将引用返回self,接下来需要签名

fn next(&'a mut self) -> Option<&'a [i8]>

然而,这与特征的签名不同,特征的签名不允许作为通用代码只需要T: Iterator<...>无法判断对某些T的返回值的使用有不同的要求;所有这些都必须以同样的方式处理。

Iterator特征是为独立于迭代器对象的返回值而设计的,这对于像.collect这样的迭代器适配器来说是正确和安全的。这对于许多用途(例如for循环内的瞬态使用)来说比限制性更具限制性,但它正是它现在的样子。我不认为我们现在有适当推广这种特性/ for循环的工具(具体来说,我认为我们需要具有更高等级生命周期的相关类型),但可能在未来。