在Rust

时间:2016-11-28 17:26:03

标签: iterator rust

我正在尝试实施列表zipper。到目前为止,我有:

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct ListZipper {
    pub focus: Option<Tile>,
    pub left: VecDeque<Tile>,
    pub right: VecDeque<Tile>,
}

impl PartialEq for ListZipper {
    fn eq(&self, other: &ListZipper) -> bool {
        self.left == other.left && self.focus == other.focus && self.right == other.right
    }
}

我现在正在尝试实现迭代器

impl Iterator for ListZipper {
    type Item = Tile;

    fn next(&mut self) -> Option<Tile> {
        self.left.iter().chain(self.focus.iter()).chain(self.right.iter()).next().map(|w| *w)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
    }
}

在我看来,这是有道理的。迭代ListZipper时,我希望迭代left,然后focus然后right。所以我链接那些迭代器,然后返回next()

如果ListZipper中的所有字段都为空,则此方法可以正常工作。只要一个不为空,迭代ListZipper就会导致无限循环。

问题不在于链条。如果我用例如self.left.iter()left不为空,问题是一样的。同样适用于focusright

我尝试打印迭代器中的所有元素,它似乎从前到后经过VecDeque,然后卡住了。即next()在光标到达后面时不会前进。

为什么?

我意识到我可能不希望ListZipper本身成为迭代器,但这是另一个讨论。

1 个答案:

答案 0 :(得分:5)

正如评论中所提到的,你的迭代器缺少一个关键的状态:它在迭代中的距离。每次调用next时,它都会从头开始构造另一个迭代器并获取第一个元素。

这是一个简化的例子:

struct ListZipper {
    focus: Option<u8>,
}

impl Iterator for ListZipper {
    type Item = u8;

    fn next(&mut self) -> Option<Self::Item> {
        self.focus.iter().next().cloned()
    }
}

fn main() {
    let lz = ListZipper { focus: Some(42) };
    let head: Vec<_> = lz.take(5).collect();
    println!("{:?}", head); // [42, 42, 42, 42, 42]
}
  

我意识到我可能不希望ListZipper本身成为迭代器,但这是另一个讨论。

不,这真的不是^ _ ^。您需要以某种方式改变正在迭代的事物,以便它可以更改并为每个后续调用设置不同的值。

如果要返回现有迭代器和迭代器适配器的组合,请参阅Correct way to return an Iterator?以获取说明。

否则,您需要在调用ListZipper期间以某种方式更改next

impl Iterator for ListZipper {
    type Item = Tile;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(v) = self.left.pop_front() {
            return Some(v);
        }

        if let Some(v) = self.focus.take() {
            return Some(v);
        }

        if let Some(v) = self.right.pop_front() {
            return Some(v);
        }

        None
    }
}

更简洁:

impl Iterator for ListZipper {
    type Item = Tile;

    fn next(&mut self) -> Option<Self::Item> {
        self.left.pop_front()
            .or_else(|| self.focus.take())
            .or_else(|| self.right.pop_front())
    }
}

请注意,您的PartialEq实施似乎与自动派生的实施相同......

use std::collections::VecDeque;

type Tile = u8;

#[derive(Debug, Clone, PartialEq)]
pub struct ListZipper {
    pub focus: Option<Tile>,
    pub left: VecDeque<Tile>,
    pub right: VecDeque<Tile>,
}

impl Iterator for ListZipper {
    type Item = Tile;

    fn next(&mut self) -> Option<Self::Item> {
        self.left.pop_front()
            .or_else(|| self.focus.take())
            .or_else(|| self.right.pop_front())
    }
}

fn main() {
    let lz = ListZipper {
        focus: Some(42),
        left: vec![1, 2, 3].into(),
        right: vec![97, 98, 99].into(),
    };

    let head: Vec<_> = lz.take(5).collect();

    println!("{:?}", head);
}