Ce face IntoIterator
for x in valoare apelează de fapt IntoIterator::into_iter(valoare) și apoi next() pe rezultat. Orice tip care implementează IntoIterator poate sta după in: vectori, tablouri, intervale (0..10), HashMap, Option, referințe la colecții, iteratori (orice iterator este și IntoIterator).
Colecțiile au de obicei trei implementări: pentru Vec<T> (produce T, consumă vectorul), pentru &Vec<T> (produce &T) și pentru &mut Vec<T> (produce &mut T). De aceea for x in &v nu consumă vectorul, iar for x in v îl consumă. Din ediția 2021, tablourile se parcurg prin valoare: for x in [1, 2, 3] dă i32.
În funcții, parametrul impl IntoIterator<Item = T> acceptă orice sursă de valori: un vector, un tablou, un interval sau un lanț de adaptoare.
Ce returnează
into_iter() returnează iteratorul asociat (Self::IntoIter).
Exemple
Exemplul 1: Ce poate sta după for … in
Un Option se comportă ca o colecție cu 0 sau 1 elemente. Pentru el, compilatorul preferă totuși if let în loc de for (avertismentul for loop over an `Option`), așa că aici îl colectăm.
use std::collections::BTreeMap;
fn main() {
for x in [1, 2, 3] {
print!("{x} ");
}
println!("(tablou)");
for c in 'a'..='e' {
print!("{c}");
}
println!(" (interval de caractere)");
let poate: Option<&str> = Some("Ana");
let lista: Vec<&str> = poate.into_iter().collect();
println!("{:?} (Option cu 0 sau 1 elemente)", lista);
let m = BTreeMap::from([("Iași", 271), ("Cluj", 286)]);
for (oras, mii) in &m {
println!("{oras}: {mii} mii (dicționar)");
}
}
Rezultat
1 2 3 (tablou)
abcde (interval de caractere)
["Ana"] (Option cu 0 sau 1 elemente)
Cluj: 286 mii (dicționar)
Iași: 271 mii (dicționar)
Exemplul 2: O funcție care acceptă orice sursă de numere
fn total(valori: impl IntoIterator<Item = u32>) -> u32 {
let mut s = 0;
for v in valori {
s += v;
}
s
}
fn main() {
println!("{}", total(vec![10, 20, 30]));
println!("{}", total([1, 2, 3]));
println!("{}", total(1..=100));
println!("{}", total(Some(7)));
let note = vec![9, 10];
println!("{}", total(note.iter().copied()));
}
Rezultat
60
6
5050
7
19
Exemplul 3: IntoIterator pentru un tip propriu
Implementăm trait-ul pentru Clasa (consumă clasa, dă String) și pentru &Clasa (dă &String), exact ca la Vec.
struct Clasa {
elevi: Vec<String>,
}
impl IntoIterator for Clasa {
type Item = String;
type IntoIter = std::vec::IntoIter<String>;
fn into_iter(self) -> Self::IntoIter {
self.elevi.into_iter()
}
}
impl<'a> IntoIterator for &'a Clasa {
type Item = &'a String;
type IntoIter = std::slice::Iter<'a, String>;
fn into_iter(self) -> Self::IntoIter {
self.elevi.iter()
}
}
fn main() {
let clasa = Clasa { elevi: vec![String::from("Ana"), String::from("Mihai")] };
for e in &clasa {
println!("prezent: {e}");
}
for e in clasa {
println!("absolvent: {e}");
}
}
Rezultat
prezent: Ana
prezent: Mihai
absolvent: Ana
absolvent: Mihai
Greșeli frecvente
- Scrii
for x in vși apoi foloseștiv: borrow of moved value.into_iterpeVecconsumă vectorul; scriefor x in &v. - Încerci
for c in textcu unString: `String` is not an iterator. Alege ce parcurgi:text.chars(),text.bytes()sautext.lines().
Comenzi înrudite
Iterator: Trait-ul care descrie orice șir de valori produse pe rând: next() dă următoarea valoare, sau None la final.Vec::iter: Cele trei moduri de a parcurge un vector: iter dă referințe, iter_mut dă referințe mutabile, into_iter dă elementele.FromIterator: Trait-ul tipurilor care pot fi construite dintr-un iterator; collect() îl folosește pentru a crea colecția cerută.Range: Intervalul a..b: toate valorile de la a inclusiv până la b exclusiv. Este iterator, se folosește în for și la tăierea slice-urilor.HashMap::iter: Parcurge perechile din dicționar: iter dă (&cheie, &valoare), iter_mut dă (&cheie, &mut valoare). Ordinea e aleatorie.