HashMap::drain în Rust

Golește dicționarul și dă toate perechile ca iterator, prin valoare; dicționarul rămâne gol, dar utilizabil.

Sintaxă
pub fn drain(&mut self) -> Drain<'_, K, V>

Ce face HashMap::drain

drain() scoate toate perechile (K, V), mutate, și le dă printr-un iterator. După aceea dicționarul este gol, dar își păstrează memoria și poate fi umplut din nou.

Diferența față de into_iter(): into_iter consumă dicționarul (variabila nu mai poate fi folosită), drain doar îl golește. Ca la orice parcurgere de HashMap, ordinea perechilor este aleatorie.

Ce returnează

Un iterator Drain care produce perechi (K, V).

Exemple

Exemplul 1: Trimiterea facturilor adunate

use std::collections::HashMap;

fn main() {
    let mut de_trimis = HashMap::from([(1, "factura 1"), (2, "factura 2"), (3, "factura 3")]);
    let mut lot: Vec<(i32, &str)> = de_trimis.drain().collect();
    lot.sort();
    for (id, doc) in &lot {
        println!("trimit #{id}: {doc}");
    }
    println!("rămase: {}, memorie păstrată: {}", de_trimis.len(), de_trimis.capacity() >= 3);

    de_trimis.insert(4, "factura 4");
    println!("reumplut: {:?}", de_trimis);
}

Rezultat

trimit #1: factura 1
trimit #2: factura 2
trimit #3: factura 3
rămase: 0, memorie păstrată: true
reumplut: {4: "factura 4"}

Exemplul 2: Contoare pe minut, golite la fiecare raport

use std::collections::HashMap;

fn main() {
    let mut contor: HashMap<&str, u32> = HashMap::new();
    let minute = [vec!["GET", "GET", "POST"], vec!["GET", "DELETE"]];
    for (i, cereri) in minute.iter().enumerate() {
        for &c in cereri {
            *contor.entry(c).or_default() += 1;
        }
        let mut raport: Vec<_> = contor.drain().collect();
        raport.sort();
        println!("minutul {}: {:?}", i + 1, raport);
    }
}

Rezultat

minutul 1: [("GET", 2), ("POST", 1)]
minutul 2: [("DELETE", 1), ("GET", 1)]

Greșeli frecvente

  • Te bazezi pe ordinea perechilor din drain: e aleatorie. Sortează după colectare.
  • Folosești drain când nu mai ai nevoie de dicționar: into_iter() e mai clar.

Comenzi înrudite

  • HashMap::len: len spune câte perechi cheie-valoare are dicționarul, is_empty dacă nu are niciuna, iar clear le șterge pe toate.
  • Vec::drain: Scoate din vector elementele dintr-un interval de poziții și le dă înapoi ca iterator, mutate (fără copiere).
  • HashMap::retain: Păstrează doar perechile pentru care funcția dată returnează true; restul sunt șterse dintr-o singură trecere.
  • HashMap::iter: Parcurge perechile din dicționar: iter dă (&cheie, &valoare), iter_mut dă (&cheie, &mut valoare). Ordinea e aleatorie.