2015-05-29 12 views
8

Tôi muốn xác định phương thức .unique() trên trình vòng lặp cho phép tôi lặp lại mà không trùng lặp.Làm cách nào để thêm các phương thức mới vào 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 
    } 
} 

Biên dịch này. Tuy nhiên, khi tôi cố gắng để sử dụng trong cùng một tập tin:

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

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

tôi nhận được lỗi sau:

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` 

Tôi đang làm gì sai? Làm thế nào tôi sẽ mở rộng các loại hashable tùy ý này?

Trả lời

13

Trong trường hợp cụ thể của bạn, đó là vì bạn đã triển khai đặc điểm của mình cho trình lặp của String, nhưng vectơ của bạn đang cung cấp trình lặp của &str. Dưới đây là một phiên bản chung chung hơn:

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

chung, chúng ta tạo ra một đặc điểm mới Unique đó là một subtrait của Iterator. Các đặc điểm xác định phương pháp unique, mà chỉ có giá trị để gọi khi thì mục lặp có thể là:

  1. băm
  2. So với tổng bình đẳng
  3. nhân bản vô tính

Bên cạnh đó, nó đòi hỏi rằng mục thực hiện Iterator có kích thước đã biết tại thời gian biên dịch. Điều này được thực hiện để trình vòng lặp có thể được tiêu thụ bởi bộ điều hợp lặp.

Phần quan trọng khác là việc thực hiện chăn:

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

Perfect, cảm ơn! Tôi sẽ ném cái này lên crates.io, tôi hy vọng điều đó là ổn. –

+2

@WilfredHughes Tốt thôi, nhưng bạn có thể muốn đóng góp nó vào thùng [itertools crate] (http://bluss.github.io/rust-itertools/doc/itertools/index.html), đây là một kho lưu trữ tuyệt vời cho những các loại bổ sung. – Shepmaster

+0

Ý tưởng tuyệt vời! https://github.com/bluss/rust-itertools/pull/30 –

Các vấn đề liên quan