迭代器收集的类型问题 [英] Type issue with Iterator collect
问题描述
我正在尝试使用以下代码片段将 &str
对的向量转换为 HashMap
:
I am trying to convert a vector of &str
pairs into a HashMap
with the following code snippet:
use std::collections::HashMap;
fn main() {
let pairs = vec!(("foo", "bar"), ("toto", "tata"));
let map: HashMap<&str, &str> = pairs.iter().collect();
println!("{:?}", map);
}
但是编译失败并出现此错误:
However the compilation fails with this error:
<anon>:5:47: 5:56 error: the trait `core::iter::FromIterator<&(&str, &str)>` is not implemented for the type `std::collections::hash::map::HashMap<&str, &str>` [E0277]
<anon>:5 let map: HashMap<&str, &str> = pairs.iter().collect();
但是,如果我在调用 collect()
之前添加 .cloned()
一切正常:
However if I add .cloned()
before calling collect()
everything works fine:
...
let map: HashMap<&str, &str> = pairs.iter().cloned().collect();
...
即使我理解错误消息(没有实现 FromIterator<&(&str, &str)>
类型的特征str, &str>) 我不明白类型 &(&str, &str)
来自哪里(根据 Rust 文档中的方法签名)和为什么调用 cloned()
可以解决这个问题.
Even if I understand the error message (there is no implementation of the trait FromIterator<&(&str, &str)>
for the type HashMap<&str, &str>
) I do not understand where the type &(&str, &str)
comes from (according to the method signature in the Rust documentation) and why calling cloned()
fixes that problem.
推荐答案
类型&(&str, &str)
来自什么iter()
返回:
The type &(&str, &str)
comes from what iter()
on a Vec
returns:
fn iter(&self) -> Iter<T>
在哪里 Iter<T>
实现 Iterator<Item=&T>
:
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T
...
}
换句话说,向量上的 iter()
返回一个迭代器,产生对该向量的引用.
In other words, iter()
on a vector returns an iterator yielding references into the vector.
cloned()
解决了这个问题,因为它是一个迭代器适配器,它将 Iterator
Iterator
T
是可克隆的.您可以将其视为 map(|v| v.clone())
的简写:
cloned()
solves the problem because it is an iterator adapter which converts Iterator<Item=&T>
to Iterator<Item=T>
if T
is cloneable. You can think of it as a shorthand for map(|v| v.clone())
:
let v1: Vec<i32> = vec![1, 2, 3, 4];
let v2: Vec<_> = v1.iter().cloned().collect();
let v3: Vec<_> = v1.iter().map(|v| v.clone()).collect();
assert_eq!(v2, v3);
碰巧 (&str, &str)
是可克隆的,因为每个元组组件也是可克隆的(所有引用都是),所以 cloned()
会返回一个实现 Iterator<Item=(&str, &str)>
的对象——正是 collect()
需要创建一个 HashMap
.
It happens that (&str, &str)
is cloneable because each tuple component is also cloneable (all references are), so cloned()
would return an object which implements Iterator<Item=(&str, &str)>
- exactly what collect()
needs to create a HashMap
.
或者,您可以使用 into_iter()
从 Vec
Iterator
Alternatively, you can use into_iter()
to get Iterator<Item=T>
from Vec<T>
, but then the original vector will be consumed:
use std::collections::HashMap;
fn main() {
let pairs = vec!(("foo", "bar"), ("toto", "tata"));
let map: HashMap<&str, &str> = pairs.into_iter().collect();
println!("{:?}", map);
}
这篇关于迭代器收集的类型问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!