HashMap<K, V> menyimpan pasangan kunci (key, tipe K) dan nilai (value, tipe V): kamu mencari nilai lewat kuncinya, bukan lewat nomor urut seperti di Vec. Bayangin daftar harga di dinding kasir Kedai Martabak Bang Rusdi. Kasir mencari "es teh" dan ketemu 5000, tanpa peduli es teh ada di baris ke berapa. Di bawahnya ada kertas turus untuk menghitung pesanan per menu: tiap ada pesanan, cari baris menunya lalu tambah satu coretan, dan menu yang baru pertama kali dipesan dapat baris baru yang mulai dari 0. Nama menu itu kunci, harga atau jumlah coretan itu nilai.
🧪 Tebakan cepat: tiga menu dimasukkan berurutan, martabak manis, martabak telur, lalu es teh, kemudian dicetak dengan
for (menu, harga) in &harga_menu. Dalam urutan apa barisnya tercetak? Tebak dulu, jawabannya ada di bagian "Urutannya gak bisa diandalkan".
Membuat HashMap, insert, dan get
use std::collections::HashMap;
fn main() {
let mut harga_menu: HashMap<String, u32> = HashMap::new();
harga_menu.insert(String::from("martabak manis"), 32000);
harga_menu.insert(String::from("martabak telur"), 38000);
harga_menu.insert(String::from("es teh"), 5000);
println!("Jumlah menu: {}", harga_menu.len());
println!("{:?}", harga_menu.get("es teh"));
println!("{:?}", harga_menu.get("kopi"));
match harga_menu.get("martabak telur") {
Some(harga) => println!("Martabak telur: {}", harga),
None => println!("Gak ada di menu"),
}
let lama = harga_menu.insert(String::from("es teh"), 6000);
println!("{:?} {}", lama, harga_menu.len());
}
Jumlah menu: 3
Some(5000)
None
Martabak telur: 38000
Some(5000) 3
HashMapgak ikut dimuat otomatis sepertiVecdanString. Ia ada distd::collections, jadi barisuse std::collections::HashMap;wajib di atas file.HashMap<String, u32>: kuncinyaString, nilainyau32. Seperti Vec, variabelnyalet mutsupaya bisa di-insert..insert(kunci, nilai)menyimpan satu pasangan. Kalau kuncinya sudah ada, nilainya diganti, daninsertmemberi nilai lamanya:Some(5000). Jumlah menunya tetap 3..get(kunci)memberiSome(nilai)kalau kuncinya ada danNonekalau gak ada, misalnya"kopi". Programnya jalan terus, danmatchmemilih cabang yang sesuai.harga_menu["kopi"]juga bisa membaca, tapi kalau kuncinya gak ada, program panic denganno entry found for key. Pakai[...]cuma kalau kuncinya pasti ada.
Menghitung pesanan dengan entry().or_insert()
Ini kertas turusnya. Enam pesanan masuk, dan tiap menu dihitung:
use std::collections::HashMap;
fn main() {
let pesanan = ["martabak manis", "es teh", "martabak manis", "martabak telur", "es teh", "martabak manis"];
let mut jumlah: HashMap<&str, u32> = HashMap::new();
for menu in pesanan {
*jumlah.entry(menu).or_insert(0) += 1;
}
println!("martabak manis: {}", jumlah["martabak manis"]);
println!("es teh: {}", jumlah["es teh"]);
println!("martabak telur: {}", jumlah["martabak telur"]);
}
martabak manis: 3
es teh: 2
martabak telur: 1
| Pesanan | Baris menunya | Isi jumlah sesudahnya |
|---|---|---|
| martabak manis | belum ada: dibuat 0, lalu +1 | manis 1 |
| es teh | belum ada: dibuat 0, lalu +1 | manis 1, es teh 1 |
| martabak manis | sudah ada: +1 | manis 2, es teh 1 |
| martabak telur | belum ada: dibuat 0, lalu +1 | manis 2, es teh 1, telur 1 |
| es teh | sudah ada: +1 | manis 2, es teh 2, telur 1 |
| martabak manis | sudah ada: +1 | manis 3, es teh 2, telur 1 |
.entry(menu)mencari baris untuk kunci itu..or_insert(0)membuat baris bernilai 0 kalau belum ada, lalu memberi pinjaman yang bisa diubah ke nilainya (tipenya&mut u32).*di depan berarti "ubah nilai yang dipinjam itu". Tanpa*, compiler menolak denganbinary assignment operation `+=` cannot be applied to type `&mut u32`dan menyarankan menambah*.- Di sini kuncinya
&str, pinjaman dari teks di arraypesanan, jadi gak perluString::from.
Urutannya gak bisa diandalkan
Ini program tebakan tadi, cargo build sekali lalu dijalankan dua kali:
$ ./target/debug/kedai
martabak manis: 32000
es teh: 5000
martabak telur: 38000
$ ./target/debug/kedai
es teh: 5000
martabak telur: 38000
martabak manis: 32000
Program yang sama, urutan yang beda, dan dua-duanya bukan urutan saat insert. Itu jawaban tebakannya: urutannya gak bisa ditebak. HashMap menaruh tiap pasangan di laci yang dihitung dari kuncinya (namanya hash). Supaya orang gak bisa sengaja mengirim kunci yang menumpuk di laci yang sama dan memperlambat program, Rust mengacak rumus hash itu tiap kali program jalan (RandomState). Akibatnya urutan laci, dan urutan for, bisa berubah tiap kali jalan.
BTreeMap kalau urutan penting
BTreeMap dipakai persis seperti HashMap, tapi selalu urut menurut kuncinya:
use std::collections::BTreeMap;
fn main() {
let mut harga_menu: BTreeMap<&str, u32> = BTreeMap::new();
harga_menu.insert("martabak manis", 32000);
harga_menu.insert("martabak telur", 38000);
harga_menu.insert("es teh", 5000);
for (menu, harga) in &harga_menu {
println!("{}: {}", menu, harga);
}
println!("{:?}", harga_menu);
}
es teh: 5000
martabak manis: 32000
martabak telur: 38000
{"es teh": 5000, "martabak manis": 32000, "martabak telur": 38000}
Urutannya alfabetis menurut kunci, sama di tiap kali jalan. Ingat: urut menurut kunci, bukan menurut urutan insert. Pakai HashMap kalau cuma perlu mencari lewat kunci (paling umum), BTreeMap kalau hasilnya harus dicetak urut.
⚠️ Jebakan yang sering ketemu
- Lupa
use. Tanpause std::collections::HashMap;, compiler menolak dengancannot find type `HashMap` in this scopedan menyarankan barisuseitu. - Mengandalkan urutan. Urutan
fordi HashMap bisa beda tiap kali jalan. Pakai BTreeMap kalau urutan penting. map["kunci"]untuk kunci yang belum pasti. Panic:no entry found for key. Pakai.get()lalumatch.- Lupa
*.jumlah.entry(menu).or_insert(0) += 1ditolak. Tulis*jumlah.entry(menu).or_insert(0) += 1. - Kunci String dipindah.
harga_menu.insert(nama, 5000)memindahkanStringnamake dalam HashMap, jadinamagak bisa dipakai lagi (borrow of moved value).
TL;DR: HashMap<K, V> menyimpan pasangan kunci dan nilai, dan butuh use std::collections::HashMap;. insert menyimpan (mengganti nilai lama kalau kuncinya sudah ada), get memberi Some(&nilai) atau None, dan map["kunci"] panic kalau kuncinya gak ada. Untuk menghitung, *map.entry(kunci).or_insert(0) += 1: baris baru mulai dari 0, * mengubah nilainya. Urutan for di HashMap gak bisa diandalkan (rumus hash-nya diacak tiap kali jalan), jadi pakai BTreeMap kalau hasilnya harus urut menurut kunci.