如何向迭代器添加新方法? [英] How can I add new methods to Iterator?

查看:17
本文介绍了如何向迭代器添加新方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在迭代器上定义一个 .unique() 方法,使我能够在没有重复的情况下进行迭代.

I want to define a .unique() method on iterators that enables me to iterate without duplicates.

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

这就编译了.但是,当我尝试在同一个文件中使用时:

This compiles. However, when I try to use in the same file:

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

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

我收到以下错误:

error[E0599]: no method named `unique` found for type `std::slice::Iter<'_, &str>` in the current scope
  --> src/main.rs:37:25
   |
37 |     for s in foo.iter().unique() {
   |                         ^^^^^^
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `unique`, perhaps you need to implement it:
           candidate #1: `Unique`

我做错了什么?我将如何扩展这种任意的可散列类型?

What am I doing wrong? How would I extend this arbitrary hashable types?

推荐答案

在你的特殊情况下,这是因为你已经为 String 的迭代器实现了你的特征,但是你的向量提供了一个迭代器&str.这是一个更通用的版本:

In your particular case, it's because you have implemented your trait for an iterator of String, but your vector is providing an iterator of &str. Here's a more generic version:

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

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

impl<I> Iterator for Unique<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
    }
}

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

impl<I: Iterator> UniqueExt for I {}

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

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

从广义上讲,我们创建了一个名为 UniqueExt 的新扩展特征,它具有 Iterator 作为超特征.当 Iterator 是超特征时,我们将可以访问 关联类型 Iterator::Item.

Broadly, we create a new extension trait called UniqueExt which has Iterator as a supertrait. When Iterator is a supertrait, we will have access to the associated type Iterator::Item.

这个 trait 定义了 unique 方法,只有当迭代项可以是:

This trait defines the unique method, which is only valid to call when then iterated item can be:

  1. 散列
  2. 比较完全平等
  3. 克隆

此外,它要求实现 Iterator 的项目在编译时具有已知的大小.这样做是为了使迭代器可以被 Unique 迭代器适配器使用.

Additionally, it requires that the item implementing Iterator have a known size at compile time. This is done so that the iterator can be consumed by the Unique iterator adapter.

另一个重要的部分是一揽子实现特征的任何类型也实现了Iterator:

The other important part is the blanket implementation of the trait for any type that also implements Iterator:

impl<I: Iterator> UniqueExt for I {}

这篇关于如何向迭代器添加新方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆