在Rust中实现自定义迭代器时出现无限循环
我试图执行列表zipper。到目前为止,我有:在Rust中实现自定义迭代器时出现无限循环
#[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
不是空的,问题是一样的。同样适用于focus
和right
。
我想打印在迭代的所有元素,它似乎从前面经过VecDeque
备份,然后卡住。即当它到达后面时,next()
不会前进光标。
为什么?
我意识到我可能不希望ListZipper
自己是一个迭代器,但那是另一个讨论。
正如评论中所提到的,你的迭代器缺少一个关键的状态:在迭代中有多远,它是。每次调用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);
}
非常感谢您的详细解答。现在很清楚。感谢您对“PartialEq”的评论。 – svdc
你知道'next'每次调用都会创建一个新的迭代器吗? – mcarton