Perulangan while mengulang selama kondisi boolean bernilai true, dan if let menjalankan blok ketika satu pola cocok. Rust menggabungkan keduanya menjadi while let: perulangan yang menilai ulang polanya sebelum setiap putaran, berhenti tepat ketika pola berhenti cocok. Pola kerja ini pas untuk memproses data secara berurutan — mengosongkan daftar tugas, menguras antrian, atau melangkah dari satu keadaan ke keadaan berikutnya — karena kondisi berhentinya dinyatakan sebagai pola, bukan angka atau boolean. Chapter ini membahas while let pada Option, bentuk aslinya sebagai loop-match-break, penerapan pada mesin keadaan, serta jebakan pola yang tidak pernah gagal.
Mengosongkan Daftar Tugas #
Kasus paling klasik dari while let adalah menguras koleksi lewat method yang mengembalikan Option. Method pop pada Vec mengambil elemen paling belakang dan membungkusnya dalam Some, atau mengembalikan None ketika koleksi sudah kosong — tepat pola yang dicari while let:
fn main() {
let mut tasks = vec!["mencuci piring", "menyiram tanaman", "belanja bulanan"];
while let Some(task) = tasks.pop() {
println!("Tugas dikerjakan: {}.", task);
}
println!("Semua tugas selesai.");
}Output yang Dihasilkan:
Tugas dikerjakan: belanja bulanan.
Tugas dikerjakan: menyiram tanaman.
Tugas dikerjakan: mencuci piring.
Semua tugas selesai.Mari kita bedah mekanismenya:
- Baris 2 (
let mut tasks = vec![...];):vec!membangunVecberisi tiga tugas;Vecharusmutkarena isinya akan berkurang lewatpop. - Baris 4 (
while let Some(task) = tasks.pop() {): sebelum setiap putaran,tasks.pop()dipanggil dan hasilnya dicobakan pada polaSome(task); ketika hasilnyaSome, blok berjalan dantaskmengikat elemen yang diambil. - Baris 5 (
println!("Tugas dikerjakan: {}.", task);): variabeltaskberisi tugas pada putaran berjalan — nilainya berganti di setiap iterasi karena binding dibuat ulang oleh setiap evaluasi kondisi. - Baris 8 (
println!("Semua tugas selesai.");): baris ini tercapai ketikapopakhirnya mengembalikanNone; polaSome(task)gagal, kondisi perulangan bernilai tidak terpenuhi, dan eksekusi keluar dari loop.
Urutan tugas pada keluaran terbalik dari urutan penulisan karena pop mengambil dari ujung belakang — perilaku tumpukan last in, first out. Perhatikan pula bahwa blok perulangan tidak memeriksa None sama sekali; logika berhenti sepenuhnya diserahkan pada kegagalan pola.
while let Sebagai Pemendekan loop-match-break #
Bentuk while let pada dasarnya memadatkan pola loop yang berisi match dengan break. Perbandingan berikut menunjukkan kedua program menghasilkan keluaran yang persis sama:
fn main() {
let mut tasks = vec!["mencuci piring", "menyiram tanaman", "belanja bulanan"];
loop {
match tasks.pop() {
Some(task) => println!("Tugas dikerjakan: {}.", task),
None => break,
}
}
println!("Semua tugas selesai.");
}Output yang Dihasilkan:
Tugas dikerjakan: belanja bulanan.
Tugas dikerjakan: menyiram tanaman.
Tugas dikerjakan: mencuci piring.
Semua tugas selesai.Mari kita amati strukturnya:
- Baris 4 (
loop {): perulangan tanpa syarat — keluarnya hanya lewatbreak. - Baris 5–8 (
match tasks.pop() { Some(task) => ..., None => break, }): setiap putaran memanggilpopsekali; armSomememproses tugas, armNonemengakhiri perulangan. - Baris 4–9 versus satu baris
while let: lima baris pengendali alur pada versilooptermampatkan menjadi satu bariswhile let Some(task) = tasks.pop()— pola menempati posisi kondisi, armSomemenjadi badan perulangan, dan armNonemenjadi kondisi berhenti.
Kedua bentuk identik secara perilaku, tetapi while let menggeser fokus pembaca dari mekanisme pengulangan ke pola datanya. Kapan memilih loop penuh: ketika kondisi berhenti tidak dapat dinyatakan sebagai satu pola, misalnya perlu menangkap nilai yang dihasilkan break atau keluar dari beberapa titik berbeda.
while let pada Mesin Keadaan #
Kondisi while let juga dapat menguji pola pada variabel yang nilainya diganti dari dalam perulangan. Pola ini cocok untuk mesin keadaan: perulangan berjalan selama keadaan masih varian tertentu, dan badan perulangan yang bertugas mengganti keadaan berikutnya:
enum DeliveryStatus {
Waiting(u8),
Arrived,
}
fn main() {
let mut status = DeliveryStatus::Waiting(3);
while let DeliveryStatus::Waiting(days) = status {
println!("Paket masih menunggu ({} hari lagi).", days);
status = if days > 1 {
DeliveryStatus::Waiting(days - 1)
} else {
DeliveryStatus::Arrived
};
}
println!("Paket telah tiba.");
}Output yang Dihasilkan:
Paket masih menunggu (3 hari lagi).
Paket masih menunggu (2 hari lagi).
Paket masih menunggu (1 hari lagi).
Paket telah tiba.Mari kita bedah baris per baris:
- Baris 7 (
let mut status = DeliveryStatus::Waiting(3);): keadaan awal menunggu dengan hitungan3hari;mutdiperlukan karena badan perulangan akan mengganti nilainya. - Baris 9 (
while let DeliveryStatus::Waiting(days) = status {): kondisi menguji varianWaitingsekaligus mengikat isidays; begitustatusmenjadiArrived, pola ini gagal dan perulangan berhenti dengan sendirinya. - Baris 10 (
println!("Paket masih menunggu ...", days);): nilaidaysyang diikat kondisi dipakai di badan perulangan tanpa pencocokan ulang. - Baris 12–16 (
status = if days > 1 { ... } else { ... };): keadaan berikutnya dihitung dan ditugaskan kembali — nilai lama yang dipindahkan oleh pencocokan kondisi digantikan nilai baru pada variabel yang sama; setelah penugasan, kondisiwhile letdievaluasi lagi terhadap keadaan yang baru. - Baris 19 (
println!("Paket telah tiba.");): baris penutup tercapai ketika keadaan sudah tidak lagi cocok dengan polaWaiting.
Alur program ini menjalankan tiga putaran — days bernilai 3, 2, lalu 1 — dan berhenti pada putaran keempat karena penugasan Arrived membuat pola kondisi gagal. Seluruh pengendalian perulangan bergantung pada cocok-tidaknya satu pola terhadap keadaan terkini.
Pola yang Tidak Pernah Gagal #
while let hanya dapat berhenti lewat dua pintu: polanya gagal, atau break dipanggil. Ketika pola yang dipakai bersifat irrefutable — cocok untuk semua nilai — pintu pertama tertutup dan perulangan bergantung penuh pada break. Kompilator menandai situasi ini dengan warning:
fn main() {
let mut count = 0;
while let value = count {
count += 1;
if count >= 3 {
break;
}
}
println!("Berhenti di angka {}.", count);
}Pesan kompilator (warning):
warning: irrefutable `while let` pattern
--> main.rs:4:11
|
4 | while let value = count {
| ^^^^^^^^^^^^^^^^^
|
= note: this pattern will always match, so the loop will never exit
= help: consider instead using a `loop { ... }` with a `let` inside it
= note: `#[warn(irrefutable_let_patterns)]` on by default
warning: unused variable: `value`
--> main.rs:4:15
|
4 | while let value = count {
| ^^^^^ help: if this is intentional, prefix it with an underscore: `_value`
|
= note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
warning: 2 warnings emittedProgram ini tetap berjalan dan menghasilkan keluaran berikut:
Output yang Dihasilkan:
Berhenti di angka 3.Pengikatan value menerima nilai count apa pun adanya, sehingga kondisi perulangan tidak pernah bernilai gagal; perulangan hanya berhenti karena break pada baris 7. Warning ini bekerja seperti warning irrefutable if let pattern pada chapter sebelumnya: bukan galat, melainkan penanda bahwa konstruksi kehilangan fungsinya sebagai penyaring.
Ringkasan #
while let menilai ulang polanya sebelum setiap putaran: blok berjalan selama pola cocok, binding pola tersedia di dalam badan perulangan, dan kegagalan pola menjadi kondisi berhenti. Konstruksi ini memadatkan loop-match-break menjadi satu baris, cocok untuk menguras koleksi lewat Option maupun menggerakkan mesin keadaan yang berganti nilai dari dalam perulangan. Pola irrefutable membuat perulangan kehilangan pintu keluar alaminya dan memicu warning irrefutable while let pattern. Chapter berikutnya membahas operator @ yang memungkinkan satu pola sekaligus menguji nilai dan menyimpannya ke variabel.