Iterator vs IntoIterator per appiattire
Sto giocando con gli iteratori e li sto usando Flattenper capire meglio come funzionano gli iteratori. Questo esempio:
assert_eq!(vec![1, 2].iter().flatten().count(), 2);
Non si compila e dà l'errore (beh, l'errore principale di preoccupazione):
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}`
Ciò che mi confonde è che sembra che Flattenrichieda l'annidamento Itemper l'implementazione IntoIterator. L'ho confermato nei rustdocs, dove dichiarano
pub struct Flatten<I>
where
I: Iterator,
<I as Iterator>::Item: IntoIterator
Appena pronti i documenti, IntoIterator fornisce solo un modo per definire come un tipo viene convertito in un iteratore. Perché il tratto non poteva essere vincolato <I as Iterator>::Item: Iterator? Sicuramente se l'elemento nidificato viene implementato Iterator, allora otteniamo lo stesso Flattenpoiché gli elementi nidificati devono essere essi stessi iteratori. Quale differenza / vantaggio apporta IntoIteratorinvece all'uso ?
Risposte
Richiedere IntoIteratoranziché Iteratorconsente di appiattire una raccolta di raccolte oltre a una raccolta di iteratori.
Il tipo di raccolta, ad esempio Vec, è diverso dal tipo di iteratore, quindi se è flattennecessario che gli elementi siano Iterators non è possibile appiattire un Vecdi Vecs.
IntoIteratorrappresenta un tipo che può essere convertito in un iteratore, come una Veco molte altre raccolte (o un iteratore!). Quindi questo, ad esempio, funziona:
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);
}
Puoi provare questo esempio su Playground . L'uso di into_iter()above invece di iter()ci assicura di iterare su i32s, non sui riferimenti a i32s. (Grazie Cerberus per il suggerimento into_iter()invece di copied().)
(Puoi vedere alcuni altri tipi con IntoIteratorimplementazioni nella sezione "Implementazioni su tipi esterni" dei documenti .)