rust - 如何实现支持可变迭代器的容器?

标签 rust lifetime borrow-checker

<分区>

我想设计一个支持可变迭代器的玩具容器类,但我在整理迭代器的生命周期及其对容器的引用时遇到了问题。

我尝试创建一个最小的非编译示例:

struct Payload {
    value: i32,
}

struct Container {
    val: Payload,
}

struct IterMut<'a> {
    cont: &'a mut Container,
    cnt: i32,
}

impl<'a> Container {
    fn new() -> Container {
        Container { val: Payload { value: 42 } }
    }
    fn iter_mut(&'a mut self) -> IterMut<'a> {
        IterMut {
            cont: self,
            cnt: 10,
        }
    }
}

impl<'a> Iterator for IterMut<'a> {
    type Item = &'a mut Payload;

    fn next<'b>(&'b mut self) -> Option<Self::Item> {
        self.cnt -= 1;

        if self.cnt < 0 {
            return None;
        } else {
            Some(&mut self.cont.val)
        }
    }
}

fn main() {
    let mut cont = Container::new();

    let mut it = cont.iter_mut();
    it.next();
}

上面的目的是实现一个真正的愚蠢容器,当使用 iter_mut() 迭代时,它会返回相同的项目 10 次。

我不知道如何实现 Iterator::next

我确实设法编写了一个常规函数,它实现了与我想要的 next 相同的语义:

fn manual_next<'a, 'b>(i: &'a mut IterMut<'b>) -> Option<&'a mut Payload> {
    i.cnt -= 1;

    if i.cnt < 0 {
        return None;
    } else {
        Some(&mut i.cont.val)
    }
}

这没有帮助,因为我无法调整它来实现 Iterator::next,而且如果不实现 Iterator,我的容器就不能在我想要的 for 循环中迭代。

最佳答案

按原样实现迭代器是不可能的,因为它允许您获得对同一项目的多个可变引用,从而违反了 Rust 的别名/借用规则。幸好借用检查员发现了错误! :-)

例如,扩展您的 main 示例:

fn main() {
    let mut cont = Container::new();

    let mut it = cont.iter_mut();
    let alias_1 = it.next();
    let alias_2 = it.next();
    // alias_1 and alias_2 both would have mutable references to cont.val!
}

其他 iter_mut 迭代器(例如向量/切片上的迭代器)在每一步返回对不同项目的引用,所以不会有这个问题。

如果你真的需要迭代逻辑上可变的东西,你可以不可变地迭代,但通过 RefCell 使用内部可变性或 Cell .

manual_next 函数编译的原因是您不受 Iterator::next 签名的限制,实际上调用一次(或如果您不保留结果,则更多)。但是,如果您尝试保存结果,它会保留可变借用的 IterMut 并且您无法再次调用它:

let mut cont = Container::new();

let mut it = cont.iter_mut();
let x = manual_next(&mut it);
manual_next(&mut it);  // Error: `it` is still borrowed mutably

Playground

相比之下,Iterator::next 有一种类型,它可以将 collect 之类的事情变成一个向量。

关于rust - 如何实现支持可变迭代器的容器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42243964/

相关文章:

rust - 了解生命周期 : max lifetime and 'static

rust - 如何在不使用构建脚本的情况下仅添加特定 Rust 版本的代码?

c++ - 从类返回不正确的值

rust - 有条件地在Rust中对Vec进行排序

rust - 不能在循环中多次借用可变错误

rust - 在 Rust 中实现计算图

rust - 默认情况下是否启用可选依赖项?

gtk - 如何从回调闭包中使用按钮本身?

rust - 规避封闭借用的可变生命周期限制

Rust 不能一次多次借用 `x` 作为可变的