Ce face Iterator::map
map(|x| ...) aplică closure-ul pe fiecare element și produce rezultatul. Tipul rezultatelor poate fi diferit de cel inițial: din numere poți face texte, din structuri un câmp, din texte lungimi. Numărul de elemente rămâne același.
Ca toate adaptoarele, este leneș: nu face nimic până când iteratorul nu este consumat (de for, collect, sum, count etc.). De aceea, map se termină aproape mereu cu collect::<Vec<_>>() sau cu alt consumator. Dacă vrei doar un efect (de exemplu afișare) pentru fiecare element, folosește for sau for_each, nu map.
Atenție la referințe: v.iter().map(|x| ...) primește &T. Pentru numere, operațiile aritmetice merg direct pe referințe (x * 2), dar pentru comparații sau apeluri de funcții care cer valoarea poate trebui *x.
Parametri
| Parametru | Descriere |
|---|---|
f |
Closure-ul care primește un element și returnează valoarea transformată. |
Ce returnează
Un iterator Map care produce rezultatele lui f.
Exemple
Exemplul 1: Prețuri cu TVA și etichete
fn main() {
let preturi = vec![10.0, 25.5, 4.2];
let cu_tva: Vec<f64> = preturi.iter().map(|p| p * 1.21).collect();
println!("{:.2?}", cu_tva);
let etichete: Vec<String> = preturi.iter().map(|p| format!("{p:.2} lei")).collect();
println!("{:?}", etichete);
let lungimi: Vec<usize> = ["Iași", "Cluj-Napoca", "Arad"].iter().map(|o| o.chars().count()).collect();
println!("{:?}", lungimi);
}
Rezultat
[12.10, 30.86, 5.08]
["10.00 lei", "25.50 lei", "4.20 lei"]
[4, 11, 4]
Exemplul 2: Un câmp dintr-o listă de structuri
struct Produs {
nume: &'static str,
pret: u32,
}
fn main() {
let cos = vec![
Produs { nume: "pâine", pret: 5 },
Produs { nume: "lapte", pret: 8 },
Produs { nume: "cafea", pret: 25 },
];
let nume: Vec<&str> = cos.iter().map(|p| p.nume).collect();
let total: u32 = cos.iter().map(|p| p.pret).sum();
println!("{} = {total} lei", nume.join(" + "));
}
Rezultat
pâine + lapte + cafea = 38 lei
Exemplul 3: map fără consumator nu rulează
Primul lanț nu este consumat, așa că mesajul din closure nu apare. Îl ținem într-o variabilă (altfel compilatorul ar avertiza) și îl consumăm abia la final, cu count().
fn main() {
let note = [7, 9, 10];
let lant = note.iter().map(|n| {
println!(" rotunjesc nota {n}");
n + 1
});
println!("lanțul există, dar nu a rulat încă");
let cate = lant.count();
println!("au fost procesate {cate} note");
}
Rezultat
lanțul există, dar nu a rulat încă
rotunjesc nota 7
rotunjesc nota 9
rotunjesc nota 10
au fost procesate 3 note
Greșeli frecvente
- Scrii
v.iter().map(|x| println!("{x}"));și nu apare nimic: lanțul nu e consumat, iar compilatorul avertizează unused `Map` that must be used. Pentru efecte foloseșteforsaufor_each. - Colectezi
Vec<&T>fără să vrei:v.iter().map(|x| x)dă referințe. Folosește.copied()/.cloned()sau construiește valoarea nouă în closure. - Folosești
mapcu un closure care returneazăOptionși apoi unfilter+unwrap.filter_mapface ambele pași, fărăunwrap.
Comenzi înrudite
Iterator::filter: Păstrează doar elementele pentru care condiția dată returnează true; restul sunt sărite.Iterator::filter_map: Transformă și filtrează într-un singur pas: păstrează valorile din Some(..) returnate de funcție și sare peste None.Iterator::flat_map: flatten „turtește” un iterator de colecții într-un singur șir de valori; flat_map aplică întâi o funcție, apoi turtește.Iterator::collect: Consumă iteratorul și adună valorile într-o colecție: Vec, String, HashMap, HashSet, chiar Result sau Option.Iterator::for_each: Apelează o funcție pentru fiecare element; este echivalentul unei bucle for, scris la capătul unui lanț de adaptoare.