2015-05-29 61 views
8

我想在迭代器上定義一個.unique()方法,使我能夠不重複地進行迭代。如何向Iterator添加新方法?

use std::collections::HashSet; 

struct UniqueState<'a> { 
    seen: HashSet<String>, 
    underlying: &'a mut Iterator<Item=String> 
} 

trait Unique { 
    fn unique(&mut self) -> UniqueState; 
} 

impl Unique for Iterator<Item=String> { 
    fn unique(&mut self) -> UniqueState { 
     UniqueState { seen: HashSet::new(), underlying: self } 
    } 
} 

impl<'a> Iterator for UniqueState<'a> { 
    type Item = String; 
    fn next(&mut self) -> Option<String> { 
     while let Some(x) = self.underlying.next() { 
      if !self.seen.contains(&x) { 
       self.seen.insert(x.clone()); 
       return Some(x) 
      } 
     } 
     None 
    } 
} 

這個編譯。然而,當我嘗試在同一文件中使用:

fn main() { 
    let foo = vec!["a", "b", "a", "cc", "cc", "d"]; 

    for s in foo.iter().unique() { 
     println!("{}", s); 
    } 
} 

我得到以下錯誤:

src/main.rs:34:25: 34:33 error: no method named `unique` found for type `core::slice::Iter<'_, &str>` in the current scope 
src/main.rs:34  for s in foo.iter().unique() { 
             ^~~~~~~~ 
note: in expansion of for loop expansion 
src/main.rs:34:5: 36:6 note: expansion site 
src/main.rs:34:25: 34:33 help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `unique`, perhaps you need to implement it: 
src/main.rs:34:25: 34:33 help: candidate #1: `Unique` 

我在做什麼錯?我將如何擴展這個任意可排序類型?

回答

13

在你的特定情況下,這是因爲你已經實現了String迭代器的特性,但是你的向量提供了一個迭代器&str。下面是一個更寬泛的版本:

use std::collections::HashSet; 
use std::hash::Hash; 

struct UniqueState<I> 
    where I: Iterator 
{ 
    seen: HashSet<I::Item>, 
    underlying: I, 
} 

trait Unique: Iterator { 
    fn unique(self) -> UniqueState<Self> 
     where Self::Item: Hash + Eq + Clone, 
       Self: Sized, 
    { 
     UniqueState { seen: HashSet::new(), underlying: self } 
    } 
} 

impl<I> Unique for I where I: Iterator {} 

impl<I> Iterator for UniqueState<I> 
    where I: Iterator, 
      I::Item: Hash + Eq + Clone, 
{ 
    type Item = I::Item; 

    fn next(&mut self) -> Option<Self::Item> { 
     while let Some(x) = self.underlying.next() { 
      if !self.seen.contains(&x) { 
       self.seen.insert(x.clone()); 
       return Some(x) 
      } 
     } 
     None 
    } 
} 

fn main() { 
    let foo = vec!["a", "b", "a", "cc", "cc", "d"]; 

    for s in foo.iter().unique() { 
     println!("{}", s); 
    } 
} 

廣義上說,我們創建了一個新的特點Unique那就是Iterator一個subtrait。性狀定義unique方法,這是唯一有效的調用然後當迭代項可以是:

  1. 散列
  2. 用於克隆

此外總平等

  • 相比,它要求實施Iterator的項目在編譯時具有已知的大小。這樣做是爲了迭代器可以由Unique迭代器適配器使用消耗

    的另一個重要部分是毯實現

    impl<I> Unique for I where I: Iterator {} 
    
  • +0

    完美,謝謝!我打算把它放在crates.io上,我希望沒問題。 –

    +2

    @WilfredHughes這很好,但你可能希望將它貢獻給[itertools crate](http://bluss.github.io/rust-itertools/doc/itertools/index.html),這是一個偉大的存儲庫添加類型。 – Shepmaster

    +0

    好主意! https://github.com/bluss/rust-itertools/pull/30 –