Entry::or_insert în Rust

Dacă cheia lipsește, inserează valoarea dată; în ambele cazuri returnează o referință mutabilă la valoarea din dicționar.

Sintaxă
pub fn or_insert(self, default: V) -> &'a mut V

Ce face Entry::or_insert

m.entry(k).or_insert(v) înseamnă: „dacă k nu există, pune v; apoi dă-mi valoarea lui k”. Rezultatul este &mut V, prin care poți modifica imediat valoarea: *m.entry(k).or_insert(0) += 1 numără aparițiile.

Dacă cheia există, valoarea dată este ignorată, iar valoarea existentă rămâne. Atenție: argumentul este calculat oricum, chiar dacă nu e folosit (ca orice argument de funcție). Pentru valori scumpe de construit, folosește or_insert_with, care primește un closure apelat doar la nevoie.

Parametri

Parametru Descriere
default Valoarea inserată dacă cheia lipsește.

Ce returnează

&mut V: referință mutabilă la valoarea din dicționar (cea existentă sau cea tocmai inserată).

Exemple

Exemplul 1: Literele unui cuvânt

Afișăm sortat după literă. „ă” vine după literele fără diacritice, pentru că are un cod Unicode mai mare.

use std::collections::HashMap;

fn main() {
    let mut litere: HashMap<char, usize> = HashMap::new();
    for c in "mămăligă".chars() {
        *litere.entry(c).or_insert(0) += 1;
    }
    let mut lista: Vec<_> = litere.into_iter().collect();
    lista.sort();
    println!("{:?}", lista);
}

Rezultat

[('g', 1), ('i', 1), ('l', 1), ('m', 2), ('ă', 3)]

Exemplul 2: Vânzări totale pe oraș

use std::collections::HashMap;

fn main() {
    let vanzari = [("Iași", 120.5), ("Cluj", 80.0), ("Iași", 30.25), ("București", 200.0), ("Cluj", 19.5)];
    let mut total: HashMap<&str, f64> = HashMap::new();
    for (oras, suma) in vanzari {
        *total.entry(oras).or_insert(0.0) += suma;
    }
    let mut orase: Vec<_> = total.keys().copied().collect();
    orase.sort();
    for o in orase {
        println!("{o:10} {:8.2} lei", total[o]);
    }
}

Rezultat

București    200.00 lei
Cluj          99.50 lei
Iași         150.75 lei

Exemplul 3: Referința primită se folosește de mai multe ori

Ținem referința într-o variabilă, o modificăm de două ori și abia apoi citim din nou dicționarul.

use std::collections::HashMap;

fn main() {
    let mut scoruri = HashMap::from([("Mihai", 30)]);

    let scor = scoruri.entry("Ana").or_insert(0);
    *scor += 10;
    *scor *= 2;
    println!("Ana: {scor}");

    let scor = scoruri.entry("Mihai").or_insert(0);
    *scor += 5;
    println!("Mihai: {scor} (avea deja 30, iar 0 a fost ignorat)");
}

Rezultat

Ana: 20
Mihai: 35 (avea deja 30, iar 0 a fost ignorat)

Greșeli frecvente

  • Uiți steluța: m.entry(k).or_insert(0) += 1 dă binary assignment operation `+=` cannot be applied to type `&mut {integer}`. Scrie *m.entry(k).or_insert(0) += 1.
  • Dai ca valoare implicită ceva scump (Vec::with_capacity(1000), un calcul): se execută la fiecare apel, chiar dacă cheia există. Folosește or_insert_with.
  • Te aștepți ca or_insert(v) să suprascrie valoarea existentă. Nu o atinge; pentru suprascriere folosește insert.

Comenzi înrudite

  • HashMap::entry: Caută o cheie o singură dată și îți dă „locul” ei (Entry), ca să inserezi, să citești sau să modifici fără o a doua căutare.
  • Entry::or_insert_with: Ca or_insert, dar valoarea de inserat e calculată de un closure, apelat doar dacă cheia lipsește.
  • Entry::or_default: Dacă cheia lipsește, inserează valoarea implicită a tipului (0, vector gol, text gol) și returnează &mut V.
  • Entry::and_modify: Dacă cheia există, aplică funcția dată pe valoarea ei; returnează Entry-ul, ca să poți continua cu or_insert.