使用Iterator collect键入问题 [英] Type issue with Iterator collect

查看:116
本文介绍了使用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();

但是如果我添加 .cloned()在调用 collect()之前一切正常:

However if I add .cloned() before calling collect() everything works fine:

...
let map: HashMap<&str, &str> = pairs.iter().cloned().collect();
...

即使我理解错误信息(没有执行特征 FromIterator<&(& str,& str)> 类型 HashMap<& 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)来自 Vec 上的html#method.iterrel =noreferrer> 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< Item =& T> 转换为 Iterator< Item = T> 如果 T 是可克隆的。您可以将其视为地图的简写(| 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()来获得 Iterator< Item = T> 来自 Vec< T> ,但随后将使用原始矢量:

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);
}

这篇关于使用Iterator collect键入问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆