HashMap in Rust
Eine HashMap speichert Daten als Schlüssel-Wert-Paare. Du schlägst etwas also über einen Schlüssel nach – nicht über eine Position wie bei einem Array oder Vektor. Wenn du in Python schon ein Dictionary oder in JavaScript ein Objekt als Map benutzt hast: Das ist dieselbe Idee.
Eine HashMap erstellen
Abschnitt betitelt „Eine HashMap erstellen“use std::collections::HashMap;
fn main() { let mut ages = HashMap::new();
ages.insert("Alice", 30); ages.insert("Bob", 25);
println!("{:?}", ages);}use std::collections::HashMap; ganz oben holt den Typ in den Gültigkeitsbereich (Scope). Anders als Vec und String ist HashMap nicht automatisch verfügbar – diese Zeile brauchst du also.
Einen Wert nachschlagen
Abschnitt betitelt „Einen Wert nachschlagen“use std::collections::HashMap;
fn main() { let mut ages = HashMap::new(); ages.insert("Alice", 30);
match ages.get("Alice") { Some(age) => println!("Alice ist {age}"), None => println!("Nicht gefunden"), }}.get() gibt nicht direkt den Wert zurück, sondern eine Option – denn den Schlüssel gibt es vielleicht gar nicht. Option bekommt noch eine eigene Seite. Bis dahin ist match mit Some/None der übliche Weg, damit umzugehen.
Einen Wert aktualisieren
Abschnitt betitelt „Einen Wert aktualisieren“Fügst du denselben Schlüssel noch einmal ein, wird der alte Wert überschrieben:
use std::collections::HashMap;
fn main() { let mut ages = HashMap::new(); ages.insert("Alice", 30); ages.insert("Alice", 31); // überschreibt 30
println!("{:?}", ages.get("Alice"));}Willst du einen Wert nur dann einfügen, wenn es den Schlüssel noch nicht gibt, nimm .entry():
use std::collections::HashMap;
fn main() { let mut ages = HashMap::new(); ages.insert("Alice", 30);
ages.entry("Alice").or_insert(99); // Alice gibt es schon, also passiert nichts ages.entry("Bob").or_insert(25); // Bob gibt es noch nicht, also wird er eingefügt
println!("{:?}", ages);}Mit einer Schleife über eine HashMap laufen
Abschnitt betitelt „Mit einer Schleife über eine HashMap laufen“use std::collections::HashMap;
fn main() { let mut ages = HashMap::new(); ages.insert("Alice", 30); ages.insert("Bob", 25);
for (name, age) in &ages { println!("{name} ist {age}"); }}Wann du eine HashMap nimmst
Abschnitt betitelt „Wann du eine HashMap nimmst“Eine HashMap ist immer dann richtig, wenn du Dinge über einen Namen oder eine ID nachschlagen willst statt über eine Position: Wörter zählen, Benutzernamen ihren Daten zuordnen, Ergebnisse unter einem Schlüssel zwischenspeichern. Ist die Reihenfolge wichtig oder arbeitest du einfach eine Liste ab, passt ein Vec besser.
Übungen
Abschnitt betitelt „Übungen“1. Ein kleines Telefonbuch
Abschnitt betitelt „1. Ein kleines Telefonbuch“Speichere drei Namen mit Telefonnummern in einer HashMap. Schlag dann "Ben" nach (der drinsteht) und "Dana" (die nicht drinsteht), und gib für beide eine freundliche Zeile aus. Tipp: Lauf über ["Ben", "Dana"] und nimm ein match auf .get(name).
Lösung anzeigen
use std::collections::HashMap;
fn main() { let mut phone_book = HashMap::new(); phone_book.insert("Ana", "555-1234"); phone_book.insert("Ben", "555-9876"); phone_book.insert("Chen", "555-4321");
for name in ["Ben", "Dana"] { match phone_book.get(name) { Some(number) => println!("{name}: {number}"), None => println!("{name}: nicht im Telefonbuch"), } }}Ausgabe:
Ben: 555-9876Dana: nicht im TelefonbuchWeil wir über die gesuchten Namen laufen statt über die Map, bekommen wir außerdem eine feste Reihenfolge. Das ist ein praktischer Trick, wann immer du von einer HashMap eine vorhersagbare Ausgabe brauchst.
2. Stimmen zählen
Abschnitt betitelt „2. Stimmen zählen“Du hast die Stimmen ["rot", "blau", "rot", "grün", "blau", "rot"]. Zähle, wie viele jede Farbe bekommen hat, und gib dann die Ergebnisse für "rot", "grün", "blau" und "rosa" aus (die keine bekommen hat). Tipp: counts.entry(color).or_insert(0) liefert dir den aktuellen Zählerstand dieser Farbe, beginnend bei 0. Mit *count += 1 erhöhst du ihn um eins.
Lösung anzeigen
use std::collections::HashMap;
fn main() { let votes = ["rot", "blau", "rot", "grün", "blau", "rot"]; let mut counts = HashMap::new();
for color in votes { let count = counts.entry(color).or_insert(0); *count += 1; }
for color in ["rot", "grün", "blau", "rosa"] { match counts.get(color) { Some(n) => println!("{color}: {n}"), None => println!("{color}: 0"), } }}Ausgabe:
rot: 3grün: 1blau: 2rosa: 0or_insert(0) gibt eine veränderbare Referenz auf den Wert in der Map zurück, keine Kopie. Das * in *count += 1 bedeutet „ändere die Zahl, auf die das hier zeigt“ – so wird die Map selbst aktualisiert. Dieses Muster „entry, sonst 0 einfügen, dann 1 addieren“ ist in Rust der Standardweg, um Dinge zu zählen.
Zusammenfassung
Abschnitt betitelt „Zusammenfassung“HashMap<K, V>speichert Schlüssel-Wert-Paare. Du holst sie mituse std::collections::HashMap;in den Scope..insert(key, value)fügt ein oder überschreibt..get(key)schlägt nach und gibt eineOptionzurück..entry(key).or_insert(value)fügt nur ein, wenn es den Schlüssel noch nicht gibt.- Die Reihenfolge beim Durchlaufen ist nicht garantiert – verlass dich nicht darauf.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. Was brauchst du – anders als bei Vec oder String –, um HashMap in den Scope zu holen?
2. Was macht .entry(key).or_insert(value)?
3. Kannst du dich beim Durchlaufen einer HashMap auf die Reihenfolge der Einträge verlassen?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- Schlüssel mit zugehörigen Werten in Hashtabellen ablegen – Das Rust-Buch: behandelt die Ownership von Schlüsseln und Werten und ein Beispiel zum Wörterzählen, das Werte aktualisiert.
- HashMap – Rust by Example (auf Englisch): ein ausführbares Kontaktlisten-Beispiel mit
insert,get,removeund Schleifen. HashMap– Doku der Standardbibliothek (auf Englisch): alle Methoden, daruntercontains_key,remove,keysundvalues.Entry– Doku der Standardbibliothek (auf Englisch): alles, was du mit.entry()machen kannst, etwaor_insert_withundand_modify.