我遇到了一个问题,可以简化为以下几点:

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特性似乎没有直接提供此类功能.即使有一些排列,比如只保留迭代器本身中对向量的引用,或者使迭代器成为引用,或者让生命周期更早地烘焙到类型中,我也无法通过borrow 判断器.

我读了"Iterators yielding mutable references"博客,但我不确定它是否适用于我的问题,不涉及可变引用.

推荐答案

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

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

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

然而,这不同于特征的签名,特征不被允许作为仅取T: Iterator<...>的泛型代码,不能说明对某些T的返回值的使用有不同的要求;所有这些都必须以相同的方式处理.

Iterator trait是为独立于迭代器对象的返回值而设计的,这对于像.collect这样的迭代器适配器是正确和安全的.这比许多用途(例如for环路内的瞬时使用)所需的限制更大,但目前的情况正是如此.我认为我们现在还没有合适的工具来概括这个特性/for循环(具体来说,我认为我们需要具有更高秩生存期的关联类型),但可能在将来.

Rust相关问答推荐

if let声明中临时对象的生存期

Rust kill std::processs::child

什么是Rust惯用的方式来使特征向量具有单个向量项的别名?

Rust TcpStream不能在读取后写入,但可以在不读取的情况下写入.为什么?

限制未使用的泛型导致编译错误

关于如何初始化弱 struct 字段的语法问题

如何用Axum/Tower压缩Html内容?

像这样的铁 rust 图案除了‘选项’之外,还有其他 Select 吗?

为什么基于高山Linux的Docker镜像不能在绝对路径下找到要执行的命令?

Rust将String上的迭代器转换为&;[&;str]

用于实现获取 struct 体 id 的特征规范

为什么 js_sys Promise::new 需要 FnMut?

需要一个有序向量来进行 struct 初始化

为什么Rust中无法推断生命周期?

Rust: 目标成员属于哪个"目标家族"的列表是否存在?

是否可以通过可变引用推进可变切片?

不能将 `*self` borrow 为不可变的,因为它也被borrow 为可变的 - 编译器真的需要如此严格吗?

为什么在 rust 中删除 vec 之前应该删除元素

无法把握借来的价值不够长寿,请解释

如果我不想运行析构函数,如何移出具有析构函数的 struct ?