首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何实现支持可变迭代器的容器?

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

Stack Overflow用户
提问于 2017-02-15 08:19:42
回答 1查看 1.1K关注 0票数 5

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

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

代码语言:javascript
复制
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相同的语义。

代码语言:javascript
复制
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-循环中迭代,这是我想要的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-02-15 09:19:25

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

例如,扩展main示例:

代码语言:javascript
复制
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迭代器(例如,向量/片上的迭代器)在每个步骤中返回对不同项的引用,因此没有这个问题。

如果您确实需要在逻辑上可变的东西上迭代,您可能可以不变异地迭代,但是可以通过RefCellCell使用内部可变性。

manual_next函数编译的原因是您不受Iterator::next签名的限制,而且实际上只调用一次(如果不保留结果的话)是完全安全的。但是,如果您试图保存结果,它会使IterMut不断借来,您无法再次调用它:

代码语言:javascript
复制
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这样的东西成为可能。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42243964

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档