Iterator vs IntoIterator para aplanar
Estoy jugando con iteradores y he estado usando Flattenpara comprender mejor cómo funcionan los iteradores. Este ejemplo:
assert_eq!(vec![1, 2].iter().flatten().count(), 2);
No se compila y da el error (bueno, el error principal de preocupación):
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}`
Lo que me confunde es que parece que Flattenrequiere la Itemimplementación anidada IntoIterator. Confirmé esto en los rustdocs, donde declaran
pub struct Flatten<I>
where
I: Iterator,
<I as Iterator>::Item: IntoIterator
Solo desde que están listos los documentos, IntoIterator solo proporciona una forma de definir cómo se convierte un tipo en un iterador. ¿Por qué no podría ser el rasgo ligado <I as Iterator>::Item: Iterator? Seguramente si el elemento anidado se implementa Iterator, obtenemos lo mismo Flattenya que los elementos anidados deben ser iteradores. ¿Qué diferencia / beneficio aporta el uso IntoIteratoren su lugar?
Respuestas
Requerir en IntoIteratorlugar de le Iteratorpermite aplanar una colección de colecciones además de una colección de iteradores.
El tipo de colección, por ejemplo Vec, es diferente del tipo de iterador, por lo que si se flattenrequiere que los elementos sean Iterators, no podría aplanar una Vecde Vecs.
IntoIteratorrepresenta un tipo que se puede convertir en un iterador, como una Veco muchas otras colecciones (¡o un iterador!). Entonces esto, por ejemplo, funciona:
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);
}
Puedes probar este ejemplo en Playground . Usar into_iter()arriba en lugar de iter()asegura que iteramos sobre i32s, no referencias a i32s. (Gracias Cerberus por sugerir en into_iter()lugar de copied().)
(Puede ver algunos tipos más con IntoIteratorimplementaciones en la sección "Implementaciones en tipos externos" de los documentos ).