【问题标题】:Type issue with Iterator collect迭代器收集的类型问题
【发布时间】:2015-11-28 01:37:18
【问题描述】:

我正在尝试使用以下代码 sn-p 将 &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();

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

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

即使我理解错误消息(HashMap&lt;&amp;str, &amp;str&gt; 类型没有特征 FromIterator&lt;&amp;(&amp;str, &amp;str)&gt; 的实现)我也不明白 &amp;(&amp;str, &amp;str) 类型来自哪里(根据 Rust 文档中的方法签名) 以及为什么调用 cloned() 可以解决这个问题。

【问题讨论】:

    标签: iterator rust


    【解决方案1】:

    问题是,虽然引用可以被复制,但元组不能。

    但是,如果您不再需要这些对,则可以按值进行迭代:

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

    【讨论】:

      【解决方案2】:

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

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

      Iter&lt;T&gt; 在哪里实现Iterator&lt;Item=&amp;T&gt;

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

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

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

      碰巧(&amp;str, &amp;str) 是可克隆的,因为每个元组组件也是可克隆的(所有引用都是),所以cloned() 将返回一个实现Iterator&lt;Item=(&amp;str, &amp;str)&gt; 的对象——这正是collect() 创建HashMap 所需要的.

      或者,您可以使用into_iter()Vec&lt;T&gt; 获取Iterator&lt;Item=T&gt;,但随后将消耗原始向量:

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

      【讨论】:

        猜你喜欢
        • 2012-10-15
        • 2016-11-15
        • 2020-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-18
        相关资源
        最近更新 更多