2015-05-29 5 views
8

Ich möchte eine .unique() Methode für Iteratoren definieren, die es mir ermöglicht, ohne Duplikate zu iterieren.Wie kann ich neue Methoden zu Iterator hinzufügen?

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 
    } 
} 

Dies kompiliert. Allerdings, wenn ich versuchen, in der gleichen Datei zu verwenden:

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

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

ich die folgende Fehlermeldung erhalten:

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` 

Was mache ich falsch? Wie würde ich diese willkürlichen hashbaren Typen erweitern?

Antwort

13

In Ihrem speziellen Fall liegt das daran, dass Sie Ihr Merkmal für einen Iterator String implementiert haben, aber Ihr Vektor liefert einen Iterator &str. Hier ist eine generische Ausführung:

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

Im Großen und Ganzen schaffen wir ein neues Merkmal Unique, dass ein subtrait von Iterator ist. Das Merkmal definiert die unique Methode, die nur gültig ist, zu rufen, wenn dann kann iterierter Objekt sein:

  1. Gehashte
  2. Im Vergleich zur Gesamt Gleichheit
  3. Geklonten

Darüber hinaus ist es erforderlich, dass die Artikel Implementierung Iterator haben eine bekannte Größe zur Kompilierzeit. Dies geschieht, damit der Iterator von dem Unique Iterator-Adapter verbraucht werden kann.

Der andere wichtige Teil ist die Decke Umsetzung:

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

Perfect, danke! Ich werde das auf kates.io werfen, ich hoffe, das ist in Ordnung. –

+2

@ WilfredHughes Das ist in Ordnung, aber Sie können es in die [Iertools Kiste] (http://bluss.github.io/rust-itertools/doc/itertools/index.html), die ein großes Repository für diese ist beitragen Arten von Ergänzungen. – Shepmaster

+0

Ausgezeichnete Idee! https://github.com/bluss/rust-itertools/pull/30 –

Verwandte Themen