Iterator::map în Rust

Transformă fiecare valoare a iteratorului cu o funcție și dă un iterator cu rezultatele; nu calculează nimic până la consumare.

Sintaxă
fn map<B, F>(self, f: F) -> Map<Self, F>
where F: FnMut(Self::Item) -> B

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ște for sau for_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 map cu un closure care returnează Option și apoi un filter + unwrap. filter_map face 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.