Pada Chapter match Dasar, kita memakai match untuk memetakan satu nilai ke satu tindakan dengan pola literal, wildcard _, or-pattern |, dan rentang ..=. Kebutuhan pencocokan di program nyata jarang sesederhana itu: satu cabang sering harus menampung banyak nilai sekaligus, memeriksa interval yang panjang, bahkan menggabungkan pencocokan pola dengan syarat tambahan yang melibatkan variabel lain di luar nilai yang dicocokkan. Chapter ini memperdalam tiga perkakas tersebut — multi-pola |, rentang ..=, dan match guard — beserta aturan urutan arm yang menentukan cabang mana yang benar-benar dieksekusi. Pemahaman mekanisme di baliknya penting karena guard berinteraksi langsung dengan pemeriksaan exhaustiveness: kode yang secara logika sudah menutup semua kasus bisa tetap ditolak oleh kompilator.
Beberapa Pola dalam Satu Arm #
Program gudang sering memetakan banyak kode produk berbeda ke satu kategori yang sama. Menulis satu arm untuk setiap kode menghasilkan daftar cabang yang panjang padahal isinya identik. Tanda pipa | menyatukan beberapa pola menjadi satu arm: arm tersebut terpenuhi apabila nilai cocok dengan salah satu pola yang tercantum. Kompilator mencoba alternatif pada | satu per satu dari kiri, dan satu arm boleh memuat gabungan literal serta rentang sekaligus.
fn main() {
let product_code = 41;
match product_code {
1 | 2 | 3 => println!("Kategori: Elektronik."),
10 | 11 => println!("Kategori: Pakaian."),
40..=45 => println!("Kategori: Buku."),
_ => println!("Kode produk tidak dikenal."),
}
}Output yang Dihasilkan:
Kategori: Buku.Mari kita bedah kode di atas:
- Baris 2 (
let product_code = 41;): variabelproduct_codemenyimpan kode produk yang akan diperiksa, dengan nilai41. - Baris 4 (
match product_code {): pencocokan dimulai dari arm paling atas; nilai41dibandingkan dengan pola arm pertama. - Baris 5 (
1 | 2 | 3 => ...): pola gabungan memuat tiga literal; nilai41tidak sama dengan1,2, maupun3, sehingga arm ini dilewati meskipun memuat tiga alternatif. - Baris 6 (
10 | 11 => ...): nilai41juga tidak cocok dengan10atau11, sehingga pencocokan turun ke arm ketiga. - Baris 7 (
40..=45 => ...): rentang inklusif40..=45menampung seluruh nilai dari40hingga45; nilai41berada di dalamnya sehingga arm ini terpilih dan mencetak kategori Buku. - Baris 8 (
_ => ...): arm penutup menampung kode di luar semua pola di atas, misalnya99; tanpa arm ini, kompilasi gagal karena tipei32masih menyisakan kemungkinan nilai.
Perhatikan bahwa | tidak dibatasi jumlah alternatifnya, dan alternatif boleh mencampur bentuk pola — literal berdampingan dengan rentang akan kita lihat di bagian berikutnya.
Rentang Nilai dengan ..= #
Rentang ..= bekerja untuk bilangan bulat maupun char, karena kedua tipe tersebut memiliki urutan yang pasti. Rentang bersifat inklusif di kedua ujung: 90..=100 menampung 90 dan 100 beserta seluruh nilai di antaranya. Pola rentang juga dapat digabung ke dalam |, sehingga satu arm dapat menguji “literal ini, literal itu, atau nilai pada rentang berikut” tanpa memecah menjadi beberapa arm.
fn main() {
let grade = 'B';
let code = 15;
match grade {
'A'..='C' => println!("Nilai {} masuk kelompok atas.", grade),
'D'..='E' => println!("Nilai {} perlu perbaikan.", grade),
_ => println!("Huruf {} bukan nilai yang sah.", grade),
}
match code {
1 | 5 | 10..=20 => println!("Kode {} masuk daftar istimewa.", code),
_ => println!("Kode {} biasa.", code),
}
}Output yang Dihasilkan:
Nilai B masuk kelompok atas.
Kode 15 masuk daftar istimewa.Mari kita uraikan bagian-bagian pentingnya:
- Baris 6 (
'A'..='C' => ...): rentangchardibandingkan menurut urutan karakter, jadi pola ini cocok untuk'A','B', dan'C'; nilai'B'masuk sehingga kelompok atas tercetak. - Baris 7 (
'D'..='E' => ...): arm ini hanya tercapai untuk'D'dan'E'; karena'B'sudah tertangkap arm di atasnya, arm ini tidak diperiksa lagi. - Baris 8 (
_ => ...): huruf di luar'A'..='E'— misalnya'X'— jatuh ke wildcard, sehinggamatchtetap exhaustive. - Baris 12 (
1 | 5 | 10..=20 => ...): satu arm memuat dua literal dan satu rentang; nilai15tidak sama dengan1atau5, tetapi berada di dalam10..=20, sehingga arm terpenuhi.
Match Guard #
Pencocokan nilai ujian ke predikat pada Chapter sebelumnya hanya memeriksa satu angka. Kriteria kelulusan nyata sering melibatkan data kedua: nilai minimal 80 tetap gagal predikat apabila kehadiran di bawah 75 persen. Kondisi semacam ini tidak dapat dinyatakan dengan pola murni, karena pola hanya melihat nilai yang dicocokkan. Rust menyediakan match guard: kata kunci if yang ditempatkan setelah pola, sehingga arm hanya terpilih apabila polanya cocok dan guard bernilai true.
fn main() {
let score = 85;
let attendance = 60;
let status = match score {
s if s >= 80 && attendance >= 75 => "lulus dengan predikat",
s if s >= 80 => "lulus, tingkatkan kehadiran",
s if s >= 60 => "lulus bersyarat",
_ => "tidak lulus",
};
println!("Status: {}.", status);
}Output yang Dihasilkan:
Status: lulus, tingkatkan kehadiran.Mari kita bedah baris per baris:
- Baris 5 (
let status = match score {): seluruhmatchmenjadi ekspresi yang hasilnya diikat ke variabelstatus; setiap arm kini berupa string&str. - Baris 6 (
s if s >= 80 && attendance >= 75 => ...): polasmengikat nilai85, lalu guard dievaluasi;attendancebernilai60sehinggaattendance >= 75bernilaifalse, dan guard menolak arm ini walau polanya cocok. - Baris 7 (
s if s >= 80 => ...): pencocokan tidak berhenti saat guard gagal — Rust turun ke arm berikutnya dan mencoba lagi;smengikat ulang nilai85, guards >= 80bernilaitrue, sehingga arm ini yang menyumbang hasil. - Baris 8–9 (
s if s >= 60 => ...dan_ => ...): kedua arm ini menjadi jaring pengaman untuk nilai di bawah80; wildcard_tetap wajib agar pencakupan nilaii32genap. - Baris 12 (
println!("Status: {}.", status);): status akhir dicetak sekali setelah keputusan selesai.
Perhatikan bahwa guard pada baris 6 membaca variabel attendance yang berada di luar match — guard boleh memakai ekspresi apa pun, termasuk data dari luar nilai yang dicocokkan. Alur lengkap evaluasi satu arm dapat diringkas sebagai berikut:
Diagram di atas menegaskan urutan dua tahap pada setiap arm: kecocokan pola diperiksa lebih dulu, guard hanya dievaluasi setelah pola cocok. Ketika guard menolak, proses pencocokan berlanjut ke arm di bawahnya seolah arm tersebut tidak pernah ada.
Guard Tidak Dihitung dalam Exhaustiveness #
Pemeriksaan exhaustiveness hanya memperhitungkan pola, bukan isi guard. Kompilator menganggap guard selalu mungkin bernilai false, sekalipun syaratnya tampak selalu benar seperti 3 > 2. Akibatnya, match yang seluruh cakupannya bergantung pada guard akan ditolak. Program berikut memanggil varian true dari bool hanya apabila jumlah pembelian memenuhi syarat:
fn main() {
let is_member = true;
let purchases = 5;
match is_member {
true if purchases >= 3 => println!("Anggota aktif, dapat hadiah."),
false => println!("Bukan anggota."),
}
}Pesan error kompilator:
error[E0004]: non-exhaustive patterns: `true` not covered
--> main.rs:5:11
|
5 | match is_member {
| ^^^^^^^^^ pattern `true` not covered
|
= note: the matched value is of type `bool`
= note: match arms with guards don't count towards exhaustivity
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
7 ~ false => println!("Bukan anggota."),
8 ~ true => todo!(),
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0004`.Baris catatan match arms with guards don't count towards exhaustivity menyatakan aturannya secara terbuka: pola true if purchases >= 3 dianggap tidak menutup nilai true karena guard dapat menolaknya, sedangkan arm false hanya menutup false. Perbaikannya ada dua: menambahkan arm true tanpa guard sebagai penampung, atau menutup sisa dengan _.
Urutan Arm dan Pola yang Tak Terjangkau #
Karena pencocokan berjalan dari arm paling atas, penempatan _ atau rentang luas di urutan pertama membuat arm di bawahnya tidak pernah terjangkau. Kompilator tidak menjadikan kondisi ini error, melainkan memberikan warning unreachable pattern — program tetap berjalan, tetapi cabang di bawah wildcard menjadi kode mati.
fn main() {
let rating = 5;
match rating {
_ => println!("Semua rating dicatat."),
1..=5 => println!("Rating rendah."),
6..=10 => println!("Rating tinggi."),
}
}Pesan kompilator (warning):
warning: unreachable pattern
--> main.rs:6:9
|
5 | _ => println!("Semua rating dicatat."),
| - matches any value
6 | 1..=5 => println!("Rating rendah."),
| ^^^^^ no value can reach this
|
= note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default
warning: unreachable pattern
--> main.rs:7:9
|
5 | _ => println!("Semua rating dicatat."),
| - matches any value
6 | 1..=5 => println!("Rating rendah."),
7 | 6..=10 => println!("Rating tinggi."),
| ^^^^^^ no value can reach this
warning: 2 warnings emittedDua warning tersebut menandai rentang 1..=5 dan 6..=10 yang sama-sama tak terjangkau. Program kemudian tetap berjalan dan menghasilkan keluaran berikut:
Output yang Dihasilkan:
Semua rating dicatat.Arm 1..=5 dan 6..=10 tidak pernah mendapat kesempatan diperiksa karena _ pada baris 5 menangkap semua nilai. Perbaikannya sederhana: pindahkan wildcard ke posisi paling bawah setelah semua pola spesifik.
Ringkasan #
Tanda | menyatukan banyak pola dalam satu arm, rentang ..= menampung interval nilai untuk bilangan bulat dan char, dan match guard menambahkan syarat if yang hanya dievaluasi setelah pola cocok. Guard membaca variabel luar match dan menolak arm tanpa menghentikan proses pencocokan, tetapi guard tidak pernah dihitung dalam pemeriksaan exhaustiveness sehingga wildcard atau arm tanpa guard tetap dibutuhkan. Urutan arm dari spesifik ke umum mencegah pola tak terjangkau yang memicu warning kompilator. Semua pola pada chapter ini masih berupa nilai tunggal; chapter berikutnya menguraikan struct field demi field langsung di dalam pola.