Sepanjang section ini kita mengenal empat koleksi standar Rust: Vec untuk daftar berindex, HashMap untuk pasangan key-value, HashSet untuk himpunan unik, dan BTreeMap untuk key-value yang terurut. Kita menguji masing-masing dengan data belanja, skor pertandingan, stok toko, daftar hadir, dan nilai ujian. Pilihan koleksi yang tepat menentukan tiga hal sekaligus: kecepatan operasi utama, kebenaran kode (berapa banyak cabang None yang harus kita tangani), dan kejelasan niat program bagi pembaca berikutnya. Chapter penutup ini melatih refleks pemilihan — dengan satu program kecil yang menggabungkan keempat koleksi, lalu peta keputusan untuk memilih di antara mereka, termasuk koleksi tambahan yang menunggu di std::collections.
Empat Koleksi, Empat Pola Akses #
Pemilihan koleksi sebaiknya dimulai dari satu pertanyaan: bagaimana data ini diakses? Empat koleksi kita menjawab empat pola akses yang berbeda:
| Koleksi | Pola akses yang dijawab | Operasi khas |
|---|---|---|
Vec<T> | “elemen ke-N” — daftar dengan urutan dan posisi | push, insert, remove, [index] |
HashMap<K, V> | “value untuk key ini” — pencarian tunggal tercepat | insert, get, entry().or_insert() |
HashSet<T> | “apakah nilai ini sudah ada?” — keunikan | insert, contains, intersection |
BTreeMap<K, V> | “key di rentang ini, secara terurut” — keterurutan | range, first_key_value, iterasi terurut |
Baris pertama tabel memuat aturan paling sering dilupakan pemula: Vec bukan sekadar “wadah banyak data”, melainkan wadah data yang posisinya bermakna — item pertama pesanan, urutan tampilan menu, baris ke-N pada laporan. Ketika posisi tidak bermakna dan yang kita cari adalah pasangan key-value, memaksakan Vec berarti menulis pencarian manual for berikut cabang None-nya — pekerjaan yang sudah dikerjakan HashMap dengan get.
Contoh Kasus: Laporan Penjualan Toko Buku #
Saatnya keempat koleksi bekerja dalam satu program. Kasusnya: toko buku online menerima deretan pesanan, lalu mencetak rekap pendapatan per judul secara terurut:
use std::collections::{BTreeMap, HashMap, HashSet};
fn main() {
// Vec: urutan pesanan pelanggan harus terjaga
let orders = vec![
String::from("Laskar Pelangi"),
String::from("Bumi Manusia"),
String::from("Laskar Pelangi"),
];
// HashMap: pencarian harga per judul dengan key String
let mut prices = HashMap::new();
prices.insert(String::from("Bumi Manusia"), 105_000);
prices.insert(String::from("Laskar Pelangi"), 95_000);
// HashSet: mencatat judul unik yang dipesan
let mut unique_titles = HashSet::new();
// BTreeMap: rekap pendapatan, siap dicetak terurut
let mut revenue = BTreeMap::new();
for order in orders {
unique_titles.insert(order.clone());
let price = match prices.get(&order) {
Some(price) => *price,
None => 0,
};
let total = revenue.entry(order).or_insert(0);
*total += price;
}
println!("Judul unik yang dipesan: {}", unique_titles.len());
println!("Pendapatan per judul (terurut):");
for (title, total) in &revenue {
println!("- {}: Rp{}", title, total);
}
}Output yang Dihasilkan:
Judul unik yang dipesan: 2
Pendapatan per judul (terurut):
- Bumi Manusia: Rp105000
- Laskar Pelangi: Rp190000Mari kita bedah peran setiap koleksi di dalamnya:
- Baris 5-9 (
let orders = vec![...]):Vec<String>menyimpan urutan kedatangan pesanan. Pesanan ketiga memang duplikat pesanan pertama — vector membiarkannya, karena tugas vector di sini hanya menjaga urutan masuk. - Baris 12-14 (
let mut prices = HashMap::new(); ...):HashMap<String, i32>memegang daftar harga. Pola aksesnya selalu “harga untuk judul ini” — tak pernah iterasi seluruhnya, tak pernah butuh urutan — persis wilayah kerjaHashMap. - Baris 17 (
let mut unique_titles = HashSet::new();):HashSet<String>menghitung berapa judul berbeda yang dipesan hari itu. Duplikasi “Laskar Pelangi” lenyap otomatis saatinsertdi baris 23. - Baris 20 (
let mut revenue = BTreeMap::new();): rekap pendapatan harus tampil terurut abjad di laporan akhir, jadi wadahnyaBTreeMapsejak awal — bukanHashMapyang disortir di akhir. - Baris 25-28 (
match prices.get(&order)): pencarian harga mengikuti polaOption—Some(price) => *pricemengambil harga, danNone => 0menjawab skenario judul yang tidak punya harga terdaftar (misalnya buku gratis). - Baris 30-31 (
revenue.entry(order).or_insert(0)): akumulasi pendapatan memakai Entry API dari chapter sebelumnya — judul pertama memesan lahir dari0, pesanan lanjutan menambah total yang sudah ada. - Baris 36-38 (
for (title, total) in &revenue): iterasiBTreeMapmencetak hasil terurut tanpa proses sortir tambahan. “Laskar Pelangi” muncul dengan totalRp190000karena dua pesanan95_000terakumulasi di satu key.
Perhatikan bahwa tidak ada satu pun baris pencarian manual: tidak ada for yang menyisir vector untuk mencari harga, tidak ada pengecekan duplikasi yang ditulis tangan. Setiap kebutuhan jatuh ke koleksi yang memang dirancang untuk kebutuhan tersebut — itulah makna “memilih koleksi” dalam praktik.
Koleksi Lain di std::collections #
Empat koleksi utama bukan seluruh isi std::collections. Tiga anggota lain layak dikenali sejak sekarang:
VecDeque<T>— vector dua ujung: penyisipan dan penghapusan efisien di depan maupun belakang. Pilihan tepat untuk antrean sungguhan (antrian pesanan masuk dari belakang, diproses dari depan) yang padaVecterpaksa memakairemove(0)yang menggeser seluruh isi.BinaryHeap<T>— tumpukan prioritas:popselalu mengembalikan nilai terbesar. Pilihan tepat untuk tugas berprioritas, misalnya pesanan express diproses sebelum pesanan reguler.BTreeSet<T>— padananHashSetdengan keterurutan B-tree, untuk kebutuhan keunikan sekaligus laporan terurut.
Modul yang sama juga menyimpan LinkedList, namun kebutuhan yang benar-benar menuntut linked list sangat langka di praktik. Aturan pragmatis Rust berbunyi: mulai dari Vec atau HashMap, ganti hanya ketika profil akses data membuktikan kebutuhan lain. Koleksi tambahan ini tidak kita bahas mendalam di section dasar; cukup tahu mereka menunggu di lemari yang sama.
Daftar Periksa Sebelum Memilih #
Empat pertanyaan berikut memetakan hampir semua keputusan pemilihan koleksi:
- Apa pola akses dominannya? Posisi berindex →
Vec. Key menuju value →HashMapatauBTreeMap. Keunikan →HashSetatauBTreeSet. - Apakah urutan penting? Tidak penting → versi hash, yang lebih cepat untuk lookup tunggal. Penting untuk tampilan, rentang, atau min/max → versi B-tree.
- Apakah duplikat sah? Sah →
Vecatau map (key unik, value bebas). Tidak sah → set. - Apakah ukuran diketahui di muka? Ya →
Vec::with_capacity(n)menghemat realokasi.
Ringkasan #
Pilihan koleksi adalah keputusan arsitektur kecil yang berdampak besar: Vec untuk daftar yang posisinya bermakna, HashMap untuk pencarian key-value tercepat, HashSet untuk keunikan, dan BTreeMap untuk keterurutan dan rentang. Program laporan toko buku menunjukkan keempatnya bekerja berdampingan — setiap kebutuhan dijawab koleksi yang memang dirancang untuknya, tanpa pencarian manual ataupun sortir tambahan. Ketika profil akses melampaui keempat pola itu, std::collections masih menyimpan VecDeque, BinaryHeap, dan BTreeSet. Dengan koleksi terkuasai, perjalanan kita melanjutkan ke realitas yang tak terhindarkan: program yang gagal — dan bagaimana Rust menanganinya lewat Result di section Penanganan Error.