Ce face Iterator::collect
collect() este consumatorul cel mai folosit: parcurge tot iteratorul și construiește o colecție din valori. Ce colecție? Cea pe care o ceri: fie din tipul variabilei (let v: Vec<i32> = ...collect();), fie cu „turbofish” (.collect::<Vec<_>>()). _ lasă compilatorul să deducă tipul elementelor.
Merge pentru orice tip care implementează FromIterator: Vec, VecDeque, String (din char-uri sau din &str-uri), HashSet, BTreeSet, HashMap și BTreeMap (din perechi (cheie, valoare)).
Un caz foarte util: un iterator de Result<T, E> poate fi colectat într-un Result<Vec<T>, E>. Rezultatul este Ok(vector) dacă toate au reușit, sau prima eroare (și oprește parcurgerea acolo). La fel, Option<Vec<T>> dintr-un iterator de Option<T>.
Ce returnează
Colecția cerută, de tipul B.
Exemple
Exemplul 1: Vec, String și turbofish
fn main() {
let numere = [3, 8, 1, 6];
let duble = numere.iter().map(|n| n * 2).collect::<Vec<_>>();
let pare: Vec<i32> = numere.iter().copied().filter(|n| n % 2 == 0).collect();
println!("duble: {:?}, pare: {:?}", duble, pare);
let initiale: String = ["Ana", "Mihai", "Ioana"].iter().filter_map(|n| n.chars().next()).collect();
println!("inițiale: {initiale}");
let fara_spatii: String = "R u s t".split(' ').collect();
println!("{fara_spatii}");
}
Rezultat
duble: [6, 16, 2, 12], pare: [8, 6]
inițiale: AMI
Rust
Exemplul 2: Mulțimi și dicționare
Pentru dicționare, iteratorul trebuie să producă perechi (tupluri cu două elemente).
use std::collections::{BTreeMap, BTreeSet, HashMap};
fn main() {
let orase = ["Iași", "Cluj", "Iași", "Brașov", "Cluj"];
let unice: BTreeSet<&str> = orase.iter().copied().collect();
println!("{:?}", unice);
let lungimi: BTreeMap<&str, usize> = unice.iter().map(|&o| (o, o.chars().count())).collect();
println!("{:?}", lungimi);
let index: HashMap<usize, &str> = orase.iter().copied().enumerate().collect();
println!("poziția 3: {}", index[&3]);
}
Rezultat
{"Brașov", "Cluj", "Iași"}
{"Brașov": 6, "Cluj": 4, "Iași": 4}
poziția 3: Brașov
Exemplul 3: Result, _>: totul sau prima eroare
Dacă un singur text nu e număr, rezultatul este eroarea lui. Pentru a sări peste valorile greșite, folosește în schimb filter_map.
fn main() {
let bune = "10 20 30";
let rele = "10 douăzeci 30";
let a: Result<Vec<u32>, _> = bune.split_whitespace().map(|s| s.parse::<u32>()).collect();
let b: Result<Vec<u32>, _> = rele.split_whitespace().map(|s| s.parse::<u32>()).collect();
println!("{:?}", a);
println!("{:?}", b);
match b {
Ok(v) => println!("suma: {}", v.iter().sum::<u32>()),
Err(e) => println!("date greșite: {e}"),
}
}
Rezultat
Ok([10, 20, 30])
Err(ParseIntError { kind: InvalidDigit })
date greșite: invalid digit found in string
Greșeli frecvente
- Scrii
let v = it.collect();fără tip: type annotations needed. Compilatorul nu știe ce colecție vrei; adaugă: Vec<_>sau::<Vec<_>>. - Colectezi
v.iter()într-unVec<i32>: elementele sunt&i32(a value of type `Vec<i32>` cannot be built from an iterator over elements of type `&i32`). Adaugă.copied()sau.cloned(). - Colectezi doar ca să numeri sau să aduni (
.collect::<Vec<_>>().len()). Alocarea e inutilă: folosește directcount()sausum().
Comenzi înrudite
FromIterator: Trait-ul tipurilor care pot fi construite dintr-un iterator; collect() îl folosește pentru a crea colecția cerută.Iterator::map: Transformă fiecare valoare a iteratorului cu o funcție și dă un iterator cu rezultatele; nu calculează nimic până la consumare.Iterator::filter: Păstrează doar elementele pentru care condiția dată returnează true; restul sunt sărite.Iterator::partition: Împarte elementele în două colecții: cele pentru care condiția e adevărată și cele pentru care e falsă.Iterator::unzip: Desparte un iterator de perechi în două colecții: una cu primele elemente, alta cu al doilea element din fiecare pereche.Iterator::sum: sum adună toate elementele, product le înmulțește; tipul rezultatului trebuie precizat.