Iterator vs IntoIterator pour aplatir
Je joue avec les itérateurs et je les utilise Flattenpour mieux comprendre le fonctionnement des itérateurs. Cet exemple:
assert_eq!(vec![1, 2].iter().flatten().count(), 2);
Ne compile pas et donne l'erreur (enfin la principale erreur préoccupante):
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}`
Ce qui me trouble, c'est qu'il semble que Flattenl' Itemimplémentation nécessite l' implémentation IntoIterator. J'ai confirmé cela dans les rustdocs, où ils déclarent
pub struct Flatten<I>
where
I: Iterator,
<I as Iterator>::Item: IntoIterator
Juste à partir de la documentation, IntoIterator fournit simplement un moyen de définir comment un type est converti en itérateur. Pourquoi le trait ne pouvait-il pas être lié <I as Iterator>::Item: Iterator? Si l'élément imbriqué est implémenté Iterator, alors nous obtenons la même chose Flattenpuisque les éléments imbriqués doivent être eux-mêmes des itérateurs. Quelle différence / avantage apporte-t-il à utiliser à la IntoIteratorplace?
Réponses
Requiring IntoIteratorplutôt que Iteratorvous permet d'aplatir une collection de collections en plus d'une collection d'itérateurs.
Le type de collection, par exemple Vec, est différent du type d'itérateur, donc si flattennécessaire, les éléments doivent être Iterators, vous ne pouvez pas aplatir un Vecde Vecs.
IntoIteratorreprésente un type qui peut être converti en un itérateur, comme une Vecou plusieurs autres collections (ou un itérateur!). Donc ceci, par exemple, fonctionne:
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);
}
Vous pouvez essayer cet exemple sur le Playground . L'utilisation de into_iter()ci-dessus au lieu de iter()garantit que nous itérons sur i32s, pas sur des références à i32s. (Merci Cerberus d'avoir suggéré into_iter()au lieu de copied().)
(Vous pouvez voir quelques types supplémentaires avec des IntoIteratorimplémentations dans la section «Implémentations sur les types étrangers» de la documentation .)