首页 文章

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

提问于
浏览
10

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

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 回答

  • 11

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

    对于编译器推理这个并允许将引用返回 self next需要签名之类的

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

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

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

相关问题