- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
因为reasons ,我想定义一个通用函数,它可以迭代表示为映射或二元组向量的键值对(或满足 IntoIterator<Item=(K, V)>
的任何其他内容,其中 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<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
的错误?而不是 HashMap
?
最佳答案
IntoIterator
提供的功能消耗 self 。
fn into_iter(self) -> Self::IntoIter
为了允许使用 IntoIterator
在不消耗集合的情况下, Vec
和 HashMap
有 IntoIterator
的实现对于 &'a Vec<T>
和 &'a HashMap<K,V,S>
, 分别。然而,它们并不完全相同。
对于 HashMap ,每个Item
是 (&K, &V)
,这不会造成问题,因为代码有效地将项目假定为强制为 &str
的键和值的 2 大小元组。 .和 &&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<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)
}
}
现在这个函数起作用了:
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 .起初听起来有点疯狂,但是......!
在这一个中,停止使用元组...并开始使用键值!
trait KeyValue<K, V> {
fn key_value(&self) -> (&K, &V) {
(self.key(), self.value())
}
fn key(&self) -> &K;
fn value(&self) -> &V;
}
impl<K, V> KeyValue<K, V> for (K, V) {
fn key(&self) -> &K {
&self.0
}
fn value(&self) -> &V {
&self.1
}
}
impl<'a, K, V> KeyValue<K, V> for &'a (K, V) {
fn key(&self) -> &K {
&self.0
}
fn value(&self) -> &V {
&self.1
}
}
fn operate<I, T, K, V>(x: I)
where I: IntoIterator<Item=T>,
T: KeyValue<K, V>,
K: AsRef<str>, V: AsRef<str>
{
for p in x {
let (ref k, ref v) = p.key_value();
println!("{}: {}", k.as_ref(), v.as_ref());
}
}
Playground .我觉得这个更符合习惯。
关于iterator - 一般遍历映射或二元组向量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41626209/
我是一名优秀的程序员,十分优秀!