由于原因,我想定义一个泛型函数,它可以迭代键值对,表示为映射,或者是2元组的向量(或任何其他满足IntoIterator
,其中K
和V
是字符串的).具体来说,我想要这个工作:
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
?
IntoIterator
消耗自己提供的功能.
fn into_iter(self) -> Self::IntoIter
为了允许使用IntoIterator
不消耗收集,双方Vec
并HashMap
有实现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);
但是,如果我们希望它能够在不消耗任何产品的情况下为两个系列工作呢?好吧,我刚刚设计了两个解决方案.
这个涉及将元组隐藏在一个新的特征背后:
/// 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> AsRefPairfor (&'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()); } }
游乐场.起初听起来有点疯狂,但是......!
在这一个中,只需停止使用元组...并开始使用键值!
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()); } }
游乐场.我发现这个更惯用.