2015-09-02 21 views
10

Próbuję przekonwertować wektor &str par w HashMap z poniższym fragmencie kodu:Rodzaj problem z Iterator zbierać

use std::collections::HashMap; 

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

Jednak Kompilacja przerywa się ten błąd:

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

jednak jeśli dodam .cloned() przed wywołaniem collect() wszystko działa poprawnie:

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

Nawet jeśli rozumiem komunikat o błędzie (nie ma realizacja cechy FromIterator<&(&str, &str)> dla typu HashMap<&str, &str>) nie rozumiem gdzie typ &(&str, &str) pochodzi z (zgodnie z podpisem metoda w dokumentacji Rust) i dlaczego dzwoni cloned() poprawki ten problem.

Odpowiedz

12

Typ &(&str, &str) pochodzi z jakiego iter() on a Vec zwrotów:

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

gdzie Iter<T> implementuje Iterator<Item=&T>:

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

Innymi słowy, iter() na wektorze zwraca iterator, podając odwołania do wektora.

cloned() rozwiązuje problemu, ponieważ jest to adapter iterator który konwertuje Iterator<Item=&T> do Iterator<Item=T> jeśli T jest Cloneable. Można myśleć o nim jako skrót dla 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); 

Zdarza się, że (&str, &str) jest Cloneable ponieważ każdy składnik krotka jest również Cloneable (wszystkie odniesienia są), więc cloned() wróci obiekt, który implementuje Iterator<Item=(&str, &str)> - dokładnie co collect() musi utworzyć HashMap.

Alternatywnie, można użyć into_iter() dostać Iterator<Item=T> z Vec<T>, ale oryginalny wektor zostaną zużyte:

use std::collections::HashMap; 

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

Problem polega na tym, że podczas gdy odniesienia mogą być kopiowane, krotki nie mogą.

Jednakże, jeśli nie trzeba już pary, można iteracyjne o wartości:

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