当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《一般地迭代地图或2元组的向量》经验,为你挑选了1个好方法。

由于原因,我想定义一个泛型函数,它可以迭代键值对,表示为映射,或者是2元组的向量(或任何其他满足IntoIterator,其中KV是字符串的).具体来说,我想要这个工作:

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适用于HashMap 的定义,但不适用于矢量:

fn operate(x: I)
    where I: IntoIterator,
          K: AsRef, V: AsRef
{
    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而不是HashMap



1> E_net4 says ..:

IntoIterator消耗自己提供的功能.

fn into_iter(self) -> Self::IntoIter

为了允许使用IntoIterator不消耗收集,双方VecHashMap有实现IntoIterator&'a Vec&'a HashMap分别.但是,它们并不完全相同.

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

实际上,如果移动向量,该函数将起作用,从而产生以下IntoIterator位置Item = (K, V):

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

但是,如果我们希望它能够在不消耗任何产品的情况下为两个系列工作呢?好吧,我刚刚设计了两个解决方案.

#1

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

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

实现它为&(K,V)(&K,&V):

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

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

现在这个功能有效:

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

游乐场.起初听起来有点疯狂,但是......!

#2

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

trait KeyValue {
    fn key_value(&self) -> (&K, &V) {
        (self.key(), self.value())
    }

    fn key(&self) -> &K;
    fn value(&self) -> &V;
}

impl KeyValue for (K, V) {
    fn key(&self) -> &K {
        &self.0
    }
    fn value(&self) -> &V {
        &self.1
    }
}

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

fn operate(x: I)
    where I: IntoIterator,
          T: KeyValue,
          K: AsRef, V: AsRef
{
    for p in x {
        let (ref k, ref v) = p.key_value();
        println!("{}: {}", k.as_ref(), v.as_ref());
    }
}

游乐场.我发现这个更惯用.

推荐阅读
可爱的天使keven_464
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有