简体   繁体   English

使用map_keys在对上扩展Iterator

[英]Extending Iterator over pairs with map_keys

I'm trying to write some simple extension methods for Rust's Iterator when it's iterating over (K, V) pairs. 我正在尝试对Rust的Iterator遍历(K, V)对进行一些简单的扩展方法。 The simplest implementation I can come up with for mapping keys involves reusing Iterator::map like so: 我可以为映射键想到的最简单的实现包括重用Iterator::map如下所示:

use std::iter::Map;

trait KeyedIterator<K, V>: Iterator<Item = (K, V)> {
    fn map_keys<R, F, G>(self, f: F) -> Map<Self, G>
    where
        Self: Sized,
        F: FnMut(K) -> R,
        G: FnMut((K, V)) -> (R, V),
    {
        self.map(|(key, value): (K, V)| (f(key), value))
    }
}

impl<I, K, V> KeyedIterator<K, V> for I where I: Iterator<Item = (K, V)> {}

However, it has this error: 但是,它有此错误:

error[E0308]: mismatched types
  --> src/lib.rs:10:18
   |
10 |         self.map(|(key, value): (K, V)| (f(key), value))
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found closure
   |
   = note: expected type `G`
              found type `[closure@src/lib.rs:10:18: 10:56 f:_]`

Shouldn't the closure implement G as it is a function from (K, V) to (R, V) ? 闭包工具G是从(K, V)(R, V)的函数吗? What am I missing here? 我在这里想念什么?

If you declare a type parameter for a type or a function, that type must be provided by the caller . 如果为类型或函数声明类型参数,则调用者必须提供该类型。 However, in your code, you are attempting to determine the type G in the body of map_keys , based on the type of the closure that is defined there. 但是,在您的代码中,您尝试根据在此定义的闭包的类型来确定map_keys主体中的G类型。

Usually, the way to have a function body determine a type is with an existential return type (eg Map<Self, impl FnMut((K, V)) -> (R, V)> . However, this is not permitted in trait methods. 通常,让函数体确定类型的方式是使用存在返回类型(例如Map<Self, impl FnMut((K, V)) -> (R, V)> 。但是,这在trait中是不允许的方法。

The pattern that is used for all the built-in iterator adapters will work for your use case though. 不过,用于所有内置迭代器适配器的模式将适用于您的用例。 That is, define a struct, which is returned by your method and make it an iterator: 也就是说,定义一个结构,该结构由您的方法返回并使其成为迭代器:

// Struct to hold the state of the iterator
struct KeyedIter<I, F> {
    iter: I,
    f: F,
}

// Make KeyedIter an iterator whenever `I` is an iterator over tuples and `F` has the 
// correct signature
impl<K, V, R, I, F> Iterator for KeyedIter<I, F>
where
    I: Iterator<Item = (K, V)>,
    F: FnMut(K) -> R,
{
    type Item = R;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(k, _v)| (self.f)(k))
    }
}

// A trait for adding the `map_keys` method
trait KeyedIterator<K, V> {
    fn map_keys<R, F>(self, f: F) -> KeyedIter<Self, F>
    where
        F: FnMut(K) -> R,
        Self: Sized;
}

// implement the trait for all iterators over tuples
impl<I, K, V> KeyedIterator<K, V> for I
where
    I: Iterator<Item = (K, V)>,
{
    fn map_keys<R, F>(self, f: F) -> KeyedIter<Self, F>
    where
        F: FnMut(K) -> R,
        Self: Sized,
    {
        KeyedIter { iter: self, f }
    }
}

The KeyedIter struct is parameterised by types that the caller knows about: the previous iterator, and the mapping function. KeyedIter结构由调用者知道的类型进行参数化:上一个迭代器和映射函数。 There is no need to try to express the type of an intermediate closure - instead it's handled lazily in the iterator's next() method. 无需尝试表达中间闭包的类型-而是在迭代器的next()方法中懒惰地对其进行处理。


See also: 也可以看看:

G is tied by the method and abstracts over the concrete type being passed in for each function call. G与方法绑定在一起,并抽象出为每个函数调用传递的具体类型。 For example: 例如:

fn print<T: core::fmt::Debug>(t: T) {
    println!("{:?}", t);
}

fn main() {
    print(1);
    print(1f64);
    print("1");
}

This means that it is not possible to return an arbitrary fixed G implementation but there are some workarounds. 这意味着不可能返回任意的固定 G实现,但是有一些解决方法。

1 - Static dispatch. 1-静态调度。 The code must be modified to receive and return the same generic: 必须修改代码以接收并返回相同的泛型:

use core::iter::Map;

trait KeyedIterator<K, V>: Iterator<Item = (K, V)> {
    fn map_keys<R, F>(self, f: F) -> Map<Self, F>
    where
        Self: Sized,
        F: FnMut((K, V)) -> (R, V),
    {
        self.map(f)
    }
}

impl<I, K, V> KeyedIterator<K, V> for I where I: Iterator<Item = (K, V)> {}

fn main() {
    let vec = vec![(1u32, 2i32), (3, 4), (5, 6)];
    println!("{:?}", vec.into_iter().map_keys(|(k, v)| (k as f64 + 0.8, v)).collect::<Vec<(f64, i32)>>());
}

2 - Dynamic dispatch. 2-动态调度。 With a little of run-time overhead, you can use Box . 有了少量的运行时开销,您可以使用Box

trait KeyedIterator<K, V>: Iterator<Item = (K, V)> {
    fn map_keys<'a, R, F: 'a>(self, mut f: F) -> Box<Iterator<Item = (R, V)> + 'a>
    where
        Self: Sized + 'a,
        F: FnMut(K) -> R
    {
        Box::new(self.map(move |(key, value): (K, V)| (f(key), value)))
    }
}

impl<I, K, V> KeyedIterator<K, V> for I where
    I: Iterator<Item = (K, V)> {}

fn main() {
    let vec = vec![(1u32, 2i32), (3, 4), (5, 6)];
    println!(
        "{:?}",
        vec.into_iter()
            .map_keys(|k| k as f64 + 0.8)
            .collect::<Vec<(f64, i32)>>()
    );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM