一般地迭代地图或2元组的向量

时间:2017-01-13 01:54:03

标签: iterator rust traits

由于reasons,我想定义一个泛型函数,它可以迭代表示为映射的键值对,或者作为2元组的向量(或满足{{1}的任何其他元素)。其中IntoIterator<Item=(K, V)>K是串联的。具体来说,我想要这个工作:

V

我有一个适用于HashMap的use std::collections::HashMap; fn main() { let vc = vec![ ("a", "foo"), ("b", "bar"), ("c", "baz") ]; operate(&vc); let mut map = HashMap::new(); map.insert("d", "blurf"); map.insert("e", "quux"); map.insert("f", "xyzzy"); operate(&map); } 定义,但不适用于矢量:

operate

我收到的错误消息是

fn operate<I, K, V>(x: I)
    where I: IntoIterator<Item=(K, V)>,
          K: AsRef<str>, V: AsRef<str>
{
    for (ref k, ref v) in x {
        println!("{}: {}", k.as_ref(), v.as_ref());
    }
}

我根本不明白。首先,它似乎是倒退,而另一方面,为什么我只收到error[E0271]: type mismatch resolving `<&std::vec::Vec<(&str, &str)> as std::iter::IntoIterator>::Item == (_, _)` --> test.rs:18:5 | 18 | operate(&vc); | ^^^^^^^ expected reference, found tuple | = note: expected type `&(&str, &str)` = note: found type `(_, _)` = note: required by `operate` 而不是Vec的错误?

2 个答案:

答案 0 :(得分:6)

IntoIterator提供的功能消耗自我。

fn into_iter(self) -> Self::IntoIter

为了允许在不使用集合的情况下使用IntoIteratorVecHashMapIntoIterator &'a Vec<T>&'a HashMap<K,V,S>的实现}}, 分别。但是,它们并不完全相同。

对于哈希映射,每个Item都是(&K, &V),这不会产生问题,因为代码有效地将项目视为2个大小的键和值强制转换为{{1 }}。而&str确实强迫&&str。 对于向量,每个&str都是Item(在这种情况下为&T),但由于函数期望&(K, V)作为迭代项,因此它当前无法处理(K, V)

的项目

实际上,如果移动向量,该函数会起作用,从而产生&(K, V) IntoIterator

Item = (K, V)

但是,如果我们希望它能够在不消耗其中任何一个的情况下为两个集合工作呢?好吧,我刚刚设计了两个解决方案。

#1

这个涉及将元组隐藏在一个新的特征背后:

let vc = vec![
    ("a", "foo"),
    ("b", "bar"),
    ("c", "baz")
];
operate(vc);

/// for stuff that can be turned into a pair of references trait AsRefPair<K, V> { fn as_ref_pair(&self) -> (&K, &V); } &(K,V)

实施此功能
(&K,&V)

现在这个功能有效:

impl<'a, K, V> AsRefPair<K, V> for (&'a K, &'a V) {
    fn as_ref_pair(&self) -> (&K, &V) {
        (self.0, self.1)
    }
}

impl<'a, K, V> AsRefPair<K, V> for &'a (K, V) {
    fn as_ref_pair(&self) -> (&K, &V) {
        (&self.0, &self.1)
    }
}

Playground。起初听起来有点疯狂,但是......!

#2

在这个中,只需停止使用元组...并开始使用键值!

fn operate<I, T, K, V>(x: I)
    where I: IntoIterator<Item=T>,
          T: AsRefPair<K, V>,
          K: AsRef<str>, V: AsRef<str>
{
    for p in x {
        let (ref k, ref v) = p.as_ref_pair();
        println!("{}: {}", k.as_ref(), v.as_ref());
    }
}

Playground。我发现这个更习惯了。

答案 1 :(得分:2)

如果您传递给函数operate()一个迭代器而不是对vector的引用,您可以使用Iterator适配器将Iterator::Item转换为您需要的内容:

operate(vc.iter().map(|&(ref a, ref b)| (a, b)));