使用Iterator collect键入问题

时间:2015-09-02 13:45:42

标签: iterator rust

我正在尝试使用以下代码段将&str对的向量转换为HashMap

use std::collections::HashMap;

fn main() {
  let pairs = vec!(("foo", "bar"), ("toto", "tata"));
  let map: HashMap<&str, &str> = pairs.iter().collect();
  println!("{:?}", map);
}

但编译失败并出现此错误:

<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(),一切正常:

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

即使我理解错误消息(类型FromIterator<&(&str, &str)>没有特征HashMap<&str, &str>的实现),我也不明白类型&(&str, &str)的来源(根据Rust文档中的方法签名)以及为什么调用cloned()修复了这个问题。

2 个答案:

答案 0 :(得分:15)

&(&str, &str)类型来自Vec上的iter()返回:

fn iter(&self) -> Iter<T>

其中Iter<T>实现Iterator<Item=&T>

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T
    ...
}

换句话说,向量上的iter()返回一个迭代器,产生对向量的引用。

cloned()解决了这个问题,因为它是一个迭代器适配器,如果Iterator<Item=&T>是可克隆的,它会将Iterator<Item=T>转换为T。您可以将其视为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

或者,您可以使用into_iter()Iterator<Item=T>获取Vec<T>,但随后将使用原始媒介:

use std::collections::HashMap;

fn main() {
    let pairs = vec!(("foo", "bar"), ("toto", "tata"));
    let map: HashMap<&str, &str> = pairs.into_iter().collect();
    println!("{:?}", map);
}

答案 1 :(得分:2)

问题在于虽然可能会复制引用,但元组却不能。

但是,如果您不再需要配对,则可以按值迭代:

<?php 
value = id;
//codings
?>