2016-11-28 121 views
1

我試圖執行列表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不是空的,問題是一樣的。同樣適用於focusright

我想打印在迭代的所有元素,它似乎從前面經過VecDeque備份,然後卡住。即當它到達後面時,next()不會前進光標。

爲什麼?

我意識到我可能不希望ListZipper自己是一個迭代器,但那是另一個討論。

+2

你知道'next'每次調用都會創建一個新的迭代器嗎? – mcarton

回答

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?的說明。

否則,您需要在通話過程中以某種方式改變ListZippernext

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); 
} 
+0

非常感謝您的詳細解答。現在很清楚。感謝您對「PartialEq」的評論。 – svdc