Iterator vs IntoIterator dla spłaszczenia
Bawię się iteratorami i używam, Flattenaby lepiej zrozumieć, jak działają iteratory. Ten przykład:
assert_eq!(vec![1, 2].iter().flatten().count(), 2);
Nie kompiluje się i podaje błąd (cóż, podstawowy błąd):
error[E0277]: `&{integer}` is not an iterator
--> src/lib.rs:59:38
|
59 | assert_eq!(vec![1, 2].iter().flatten().count(), 2);
| ^^^^^^^ `&{integer}` is not an iterator
|
= help: the trait `std::iter::Iterator` is not implemented for `&{integer}`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&{integer}`
Co mnie wprawia w zakłopotanie, to to, że wygląda na to, że zaimplementowanie Flattenwymaga zagnieżdżenia . Potwierdziłem to w rustdocs, gdzie deklarująItemIntoIterator
pub struct Flatten<I>
where
I: Iterator,
<I as Iterator>::Item: IntoIterator
Już z gotowych dokumentów, IntoIterator zapewnia sposób zdefiniowania, w jaki sposób typ jest konwertowany na iterator. Dlaczego nie mogła być związana cecha <I as Iterator>::Item: Iterator? Z pewnością, jeśli element zagnieżdżony jest implementowany Iterator, otrzymujemy to samo, Flattenponieważ element zagnieżdżony musi być sam iteratorem. Jaką różnicę / korzyść przynosi IntoIteratorzamiast tego?
Odpowiedzi
Wymaganie, IntoIteratora nie Iteratorpozwala na spłaszczenie kolekcji kolekcji oprócz kolekcji iteratorów.
Na przykład typ kolekcji Vecróżni się od typu iteratora, więc jeśli flattenwymagano, aby elementy były Iterators, nie można spłaszczyć a Vecz Vecs.
IntoIteratorreprezentuje typ, który można przekształcić w iterator, taki jak Veclub wiele innych kolekcji (lub iterator!). Więc to na przykład działa:
fn main() {
let nested_vec: Vec<Vec<i32>> = vec![vec![1, 2], vec![3, 4]];
let flat_vec: Vec<i32> = nested_vec.into_iter().flatten().collect();
println!("{:?}", flat_vec);
}
Możesz wypróbować ten przykład na placu zabaw . Użycie into_iter()powyższego zamiast iter()upewnia się, że iterujemy po i32s, a nie odwołaniach do i32s. (Dzięki Cerberusowi za sugestię into_iter()zamiast copied().)
(Możesz zobaczyć kilka innych typów z IntoIteratorimplementacjami w sekcji „Implementacje na typach obcych” w dokumentach ).