HashMap în Rust

Dicționarul din Rust: asociază fiecărei chei o valoare și o găsește foarte repede după cheie. Ordinea nu este garantată.

Sintaxă
use std::collections::HashMap;

let mut m: HashMap<K, V> = HashMap::new();
let m = HashMap::with_capacity(n);
let m = HashMap::from([(k1, v1), (k2, v2)]);

Ce face HashMap

HashMap<K, V> ține perechi cheie-valoare: nume → telefon, produs → preț, cuvânt → număr de apariții. Căutarea, inserarea și ștergerea după cheie durează, în medie, la fel de puțin indiferent câte elemente are dicționarul. Fiecare cheie apare cel mult o dată.

HashMap::new() creează un dicționar gol, HashMap::with_capacity(n) unul cu loc pentru cel puțin n perechi, iar HashMap::from([(k, v), ..]) sau collect() unul cu date. Cheile trebuie să implementeze Eq și Hash: numere întregi, String, &str, char, tupluri din acestea (dar nu f64).

Ordinea elementelor este aleatorie și diferă de la o rulare la alta: Rust folosește o funcție de dispersie cu cheie aleatorie, ca protecție împotriva atacurilor. Când afișezi, sortează cheile, sau folosește BTreeMap, care ține cheile mereu sortate. Trebuie importat cu use std::collections::HashMap;.

Parametri

Parametru Descriere
K, V Tipul cheilor și tipul valorilor. De cele mai multe ori sunt deduse din primul insert.
n La with_capacity: câte perechi să încapă fără realocare.

Ce returnează

Un dicționar gol (sau cu perechile date). Metodele lui au pagini separate.

Exemple

Exemplul 1: Capitale europene, afișate sortat

Indexarea capitale["Italia"] merge când știi că cheia există. Pentru afișare în aceeași ordine la fiecare rulare, sortăm cheile.

use std::collections::HashMap;

fn main() {
    let mut capitale = HashMap::new();
    capitale.insert("România", "București");
    capitale.insert("Franța", "Paris");
    capitale.insert("Italia", "Roma");
    capitale.insert("Spania", "Madrid");

    println!("Capitala Italiei: {}", capitale["Italia"]);
    println!("{} țări", capitale.len());

    let mut tari: Vec<_> = capitale.keys().collect();
    tari.sort();
    for t in tari {
        println!("{t}: {}", capitale[t]);
    }
}

Rezultat

Capitala Italiei: Roma
4 țări
Franța: Paris
Italia: Roma
România: București
Spania: Madrid

Exemplul 2: Ordinea aleatorie, văzută direct

Dacă afișezi direct dicționarul sau îl parcurgi, ordinea se schimbă de la o rulare la alta. Rezultatul de mai jos este de la o rulare; la tine poate fi altul.

use std::collections::HashMap;

fn main() {
    let note = HashMap::from([("Ana", 10), ("Mihai", 8), ("Ioana", 9), ("Radu", 7)]);
    println!("{:?}", note);
    for (nume, nota) in &note {
        println!("{nume}: {nota}");
    }
}

Rezultat posibil (ordinea diferă la fiecare rulare)

{"Ioana": 9, "Ana": 10, "Radu": 7, "Mihai": 8}
Ioana: 9
Ana: 10
Radu: 7
Mihai: 8

Exemplul 3: with_capacity, collect și BTreeMap pentru ordine

Construim dicționarul din doi vectori paraleli. Pentru afișare ordonată, mutăm perechile într-un BTreeMap.

use std::collections::{BTreeMap, HashMap};

fn main() {
    let produse = ["pâine", "lapte", "ouă", "unt"];
    let preturi = [5.5, 8.0, 15.0, 12.5];

    let mut h: HashMap<&str, f64> = HashMap::with_capacity(produse.len());
    for (p, pret) in produse.into_iter().zip(preturi) {
        h.insert(p, pret);
    }
    println!("{} produse, capacitate cel puțin 4: {}", h.len(), h.capacity() >= 4);

    let ordonat: BTreeMap<&str, f64> = h.into_iter().collect();
    println!("{:?}", ordonat);
}

Rezultat

4 produse, capacitate cel puțin 4: true
{"lapte": 8.0, "ouă": 15.0, "pâine": 5.5, "unt": 12.5}

Greșeli frecvente

  • Te bazezi pe ordinea în care afișează {:?} sau for: ea diferă la fiecare rulare. Sortează (let mut v: Vec<_> = m.iter().collect(); v.sort();) sau folosește BTreeMap.
  • Folosești m["cheie"] pentru o cheie care poate lipsi: programul se oprește. Folosește m.get("cheie"), care returnează Option.
  • Încerci HashMap<f64, _>: the trait bound `f64: Hash` is not satisfied. Folosește o cheie întreagă (de exemplu bani în bani, nu în lei cu virgulă) sau un BTreeMap cu un tip ordonabil.
  • Uiți importul: failed to resolve: use of undeclared type `HashMap`. Adaugă use std::collections::HashMap;.

Comenzi înrudite

  • HashMap::insert: Pune o pereche cheie-valoare în dicționar; dacă cheia exista, înlocuiește valoarea și o returnează pe cea veche.
  • HashMap::get: get caută o cheie și returnează Some(&valoare) sau None; contains_key spune doar dacă cheia există.
  • 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.
  • HashMap::iter: Parcurge perechile din dicționar: iter dă (&cheie, &valoare), iter_mut dă (&cheie, &mut valoare). Ordinea e aleatorie.
  • BTreeMap: Dicționar cu cheile mereu sortate: aceleași operații ca HashMap, dar parcurgerea și afișarea sunt în ordinea cheilor.
  • HashSet: O mulțime: ține fiecare valoare o singură dată și răspunde foarte repede dacă o valoare există. Ordinea nu e garantată.