match membandingkan satu nilai dengan daftar pola (pattern) dari atas ke bawah, lalu menjalankan cabang pertama yang cocok. Bayangin papan tarif ongkir di meja kasir Kedai Martabak Bang Rusdi. Tiap total belanja jatuh ke tepat satu baris tarif: di bawah Rp50.000 ongkirnya Rp10.000, sampai Rp99.999 ongkirnya Rp5.000, dan Rp100.000 ke atas gratis. Bang Rusdi gak mau papan yang bolong: kalau ada total yang gak punya baris, papan itu gak boleh dipasang. Total belanja itu nilai yang di-match, tiap baris tarif itu satu cabang, dan aturan "gak boleh bolong" itu yang disebut exhaustive.
🧪 Tebakan cepat: kasir menulis papan ongkirnya tanpa baris terakhir:
let ongkir = match total { 0..=49_999 => 10000, 50_000..=99_999 => 5000, };Dengan
total70000, apakah programnya mencetak 5000? Tebak dulu, jawabannya ada di bagian "Harus mencakup semua kemungkinan".
match: satu nilai, banyak cabang
fn harga(menu: &str) -> u32 {
match menu {
"martabak manis" => 32000,
"martabak telur" => 38000,
"es teh" | "es jeruk" => 5000,
_ => 0,
}
}
fn main() {
println!("{}", harga("martabak telur"));
println!("{}", harga("es jeruk"));
println!("{}", harga("kopi"));
}
38000
5000
0
- Tiap cabang (arm) ditulis
pola => hasil,. Cabang dipisah koma. - Pola dicek dari atas. Yang pertama cocok menang, sisanya dilewati.
|artinya "atau":"es teh" | "es jeruk"cocok untuk dua-duanya._adalah wildcard: cocok dengan nilai apa pun yang belum tertangkap, miripdefaultdiswitchJavaScript."kopi"gak ada di menu, jadi jatuh ke_dan hasilnya0.matchdi sini baris terakhir fungsi, tanpa titik koma, jadi hasilnya jadi hasil fungsiharga.
Range dan beberapa pola
Untuk angka, pola bisa berupa range dengan ..=, sama seperti di for:
fn main() {
let total: u32 = 32000 * 2 + 38000 * 1;
let ongkir = match total {
0..=49_999 => 10000,
50_000..=99_999 => 5000,
_ => 0,
};
println!("Total: {}, ongkir: {}", total, ongkir);
}
Output-nya Total: 102000, ongkir: 0.
total |
Cabang yang cocok | ongkir |
|---|---|---|
| 32000 | 0..=49_999 |
10000 |
| 70000 | 50_000..=99_999 |
5000 |
| 102000 | _ |
0 |
0..=49_999cocok untuk 0 sampai 49999, termasuk ujungnya.49_999sama dengan49999; garis bawahnya cuma biar gampang dibaca.- Karena
matchadalah expression, hasilnya langsung disimpan diongkir. Titik komanya ada setelah}penutup, sama sepertilet ongkir = if ...;.
Harus mencakup semua kemungkinan
Ini papan ongkir tebakan tadi, tanpa cabang _:
error[E0004]: non-exhaustive patterns: `100000_u32..=u32::MAX` not covered
--> src/main.rs:3:24
|
3 | let ongkir = match total {
| ^^^^^ pattern `100000_u32..=u32::MAX` not covered
|
= note: the matched value is of type `u32`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
5 ~ 50_000..=99_999 => 5000,
6 ~ 100000_u32..=u32::MAX => todo!(),
|
Compiler menghitung sendiri angka mana yang belum punya cabang: 100000 sampai angka u32 terbesar. Karena compile gagal, gak ada yang tercetak, termasuk untuk total 70000. Itu jawaban tebakannya: gak, programnya gak jalan sama sekali.
- Perbaikannya bisa
_ => 0,atau100_000.. => 0,(100000 ke atas). Jadi yang wajib adalah semua nilai tertangkap, bukan harus selalu ada_. - Untuk
stok_telur: u8, pola0..=2dan3..=255sudah mencakup semua 256 nilai, jadi lolos tanpa_.boolcukuptruedanfalse. - Teks (
&str) gak mungkin didaftar semuanya, jadimatchpada teks selalu butuh_. Tanpa itu:non-exhaustive patterns: `&_` not covered, plus catatana wildcard `_` is necessary.
match menghasilkan nilai
Semua cabang match yang hasilnya disimpan harus setipe, persis seperti if:
error[E0308]: `match` arms have incompatible types
--> src/main.rs:5:14
|
3 | let ongkir = match total {
| __________________-
4 | | 0..=99_999 => 10000,
| | ----- this is found to be of type `{integer}`
5 | | _ => "gratis",
| | ^^^^^^^^ expected integer, found `&str`
6 | | };
| |_____- `match` arms have incompatible types
Cabang pertama angka, jadi "gratis" ditolak. Simpan 0, lalu tulis kata "gratis" saat mencetak.
Guard dan binding @
Kadang range saja gak cukup. Guard menambah syarat if di sebuah cabang, dan nama @ pola menyimpan nilai yang cocok ke variabel:
fn cek_pesanan(porsi: u32) {
match porsi {
0 => println!("Belum ada pesanan"),
n @ 1..=5 => println!("{} porsi, langsung dimasak", n),
n if n > 20 => println!("{} porsi? Telepon dulu pembelinya", n),
n => println!("{} porsi, masuk antrean", n),
}
}
fn main() {
cek_pesanan(0);
cek_pesanan(2);
cek_pesanan(8);
cek_pesanan(25);
}
Belum ada pesanan
2 porsi, langsung dimasak
8 porsi, masuk antrean
25 porsi? Telepon dulu pembelinya
n @ 1..=5cocok untuk 1 sampai 5 dan menyimpan angkanya din.n if n > 20cocok untuk nilai apa pun, asal syaratn > 20benar. 8 gak lolos syaratnya, jadi turun ke cabang berikutnya.- Pola
nsaja (tanpa syarat) menangkap semua sisanya, sama seperti_, tapi sekalian memberi nama. - Compiler gak menghitung guard saat mengecek exhaustive, jadi tetap perlu cabang terakhir yang menangkap semuanya.
🎯 Sekilas: match dengan Option
match paling sering dipakai untuk nilai yang mungkin ada, mungkin gak. harga.get(3) pada array tiga harga gak menemukan apa-apa:
fn main() {
let harga = [32000, 38000, 5000];
match harga.get(3) {
Some(h) => println!("Harga: {}", h),
None => println!("Menu nomor 3 gak ada"),
}
}
Output-nya Menu nomor 3 gak ada. Some(h) berarti ada isinya (disimpan di h), None berarti kosong. Tipe ini namanya Option, dibahas lengkap di pelajaran Result dan Option. Kamu bakal ketemu lagi di Vec dan HashMap.
⚠️ Jebakan yang sering ketemu
- Lupa
_. ErrorE0004 non-exhaustive patterns. Tambahkan_ => ...sebagai cabang terakhir. _di atas. Cabang di bawahnya gak pernah terpilih, dan compiler memberi warningunreachable patterndengan keteranganno value can reach this. Taruh_paling bawah.- match pada
String.match menudenganmenu: Stringdan pola"es teh"ditolak:expected `String`, found `&str`. Tulismatch menu.as_str(). - Cabang beda tipe. Semua cabang yang hasilnya dipakai harus menghasilkan tipe yang sama.
TL;DR: match nilai { pola => hasil, ... } mengecek pola dari atas, dan yang pertama cocok menang. Pola bisa angka, teks, range 0..=49_999, beberapa pola dengan |, guard n if n > 20, atau binding n @ 1..=5. _ menangkap semua yang belum tertangkap. match wajib exhaustive: semua kemungkinan nilai harus punya cabang, kalau gak compile gagal dengan E0004 non-exhaustive patterns. Teks selalu butuh _, angka bisa ditutup dengan range. match adalah expression, jadi semua cabangnya harus setipe dan hasilnya bisa disimpan: let ongkir = match total { ... };.