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

avl_sweden

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

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

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();
}

上面的内容旨在实现一个真正的愚蠢的容器,当使用进行迭代时,该容器将返回10次相同的项iter_mut()

我不知道如何实现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

操场

相反,Iterator::next的类型可以使collect向量成为可能。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章