Vec::retain în Rust

Păstrează în vector doar elementele pentru care funcția dată returnează true; restul sunt șterse, în aceeași ordine.

Sintaxă
pub fn retain<F>(&mut self, f: F)
where F: FnMut(&T) -> bool

Ce face Vec::retain

retain primește un closure care se uită la fiecare element (prin referință) și răspunde cu true (păstrează) sau false (șterge). Elementele rămase își păstrează ordinea.

Este modul corect de a șterge mai multe elemente dintr-un vector după o condiție: trece o singură dată prin vector, fără problemele de indici pe care le ai cu remove într-o buclă.

Closure-ul este apelat exact o dată pe element, în ordine. Dacă vrei să și modifici elementele în timpul filtrării, folosește retain_mut (primește &mut T). Dacă ai nevoie de elementele scoase, filtrează cu iteratori (partition, extract_if).

Parametri

Parametru Descriere
f Closure-ul care primește &T și returnează true pentru elementele care rămân.

Ce returnează

Nimic; vectorul este modificat pe loc.

Exemple

Exemplul 1: Doar notele de trecere

|&n| desface referința primită, ca să lucrăm direct cu numărul.

fn main() {
    let mut note = vec![4, 9, 3, 10, 7, 5, 2];
    note.retain(|&n| n >= 5);
    println!("note de trecere: {:?}", note);
}

Rezultat

note de trecere: [9, 10, 7, 5]

Exemplul 2: Produsele fără stoc ies din listă

Closure-ul primește o referință la tuplu; modelul (_, stoc) ignoră numele și ia stocul.

fn main() {
    let mut produse = vec![("pâine", 0), ("lapte", 12), ("ouă", 30), ("unt", 0)];
    let inainte = produse.len();
    produse.retain(|(_, stoc)| *stoc > 0);
    println!("eliminate {} produse fără stoc", inainte - produse.len());
    for (nume, stoc) in &produse {
        println!("{nume}: {stoc} buc.");
    }
}

Rezultat

eliminate 2 produse fără stoc
lapte: 12 buc.
ouă: 30 buc.

Exemplul 3: retain_mut: modifică și filtrează dintr-o trecere

Fiecare abonament pierde o zi; cele ajunse la 0 zile ies din listă.

fn main() {
    let mut abonamente = vec![("Ana", 3), ("Mihai", 1), ("Ioana", 2)];
    for zi in 1..=3 {
        abonamente.retain_mut(|(_, zile)| {
            *zile -= 1;
            *zile > 0
        });
        println!("după ziua {zi}: {:?}", abonamente);
    }
}

Rezultat

după ziua 1: [("Ana", 2), ("Ioana", 1)]
după ziua 2: [("Ana", 1)]
după ziua 3: []

Greșeli frecvente

  • Inversezi condiția: retain păstrează elementele pentru care closure-ul spune true, nu le șterge.
  • Încerci să modifici elementul în closure-ul lui retain: primești &T, nu &mut T. Folosește retain_mut.
  • Ștergi cu remove(i) într-o buclă pe indici. Indicii se decalează după fiecare ștergere; retain rezolvă problema dintr-o singură trecere.

Comenzi înrudite

  • Vec::dedup: Șterge elementele egale aflate unul după altul; dedup_by_key compară după o cheie calculată din fiecare element.
  • Vec::drain: Scoate din vector elementele dintr-un interval de poziții și le dă înapoi ca iterator, mutate (fără copiere).
  • Vec::swap_remove: Scoate elementul de pe o poziție și pune în locul lui ultimul element; este instantaneu, dar schimbă ordinea.
  • Iterator::filter: Păstrează doar elementele pentru care condiția dată returnează true; restul sunt sărite.
  • HashMap::retain: Păstrează doar perechile pentru care funcția dată returnează true; restul sunt șterse dintr-o singură trecere.