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:

rust
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:

text
Tugas dikerjakan: belanja bulanan.
Tugas dikerjakan: menyiram tanaman.
Tugas dikerjakan: mencuci piring.
Semua tugas selesai.

Mari kita bedah mekanismenya:

  1. Baris 2 (let mut tasks = vec![...];): vec! membangun Vec berisi tiga tugas; Vec harus mut karena isinya akan berkurang lewat pop.
  2. Baris 4 (while let Some(task) = tasks.pop() {): sebelum setiap putaran, tasks.pop() dipanggil dan hasilnya dicobakan pada pola Some(task); ketika hasilnya Some, blok berjalan dan task mengikat elemen yang diambil.
  3. Baris 5 (println!("Tugas dikerjakan: {}.", task);): variabel task berisi tugas pada putaran berjalan — nilainya berganti di setiap iterasi karena binding dibuat ulang oleh setiap evaluasi kondisi.
  4. Baris 8 (println!("Semua tugas selesai.");): baris ini tercapai ketika pop akhirnya mengembalikan None; pola Some(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:

rust
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:

text
Tugas dikerjakan: belanja bulanan.
Tugas dikerjakan: menyiram tanaman.
Tugas dikerjakan: mencuci piring.
Semua tugas selesai.

Mari kita amati strukturnya:

  1. Baris 4 (loop {): perulangan tanpa syarat — keluarnya hanya lewat break.
  2. Baris 5–8 (match tasks.pop() { Some(task) => ..., None => break, }): setiap putaran memanggil pop sekali; arm Some memproses tugas, arm None mengakhiri perulangan.
  3. Baris 4–9 versus satu baris while let: lima baris pengendali alur pada versi loop termampatkan menjadi satu baris while let Some(task) = tasks.pop() — pola menempati posisi kondisi, arm Some menjadi badan perulangan, dan arm None menjadi 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:

rust
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:

text
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:

  1. Baris 7 (let mut status = DeliveryStatus::Waiting(3);): keadaan awal menunggu dengan hitungan 3 hari; mut diperlukan karena badan perulangan akan mengganti nilainya.
  2. Baris 9 (while let DeliveryStatus::Waiting(days) = status {): kondisi menguji varian Waiting sekaligus mengikat isi days; begitu status menjadi Arrived, pola ini gagal dan perulangan berhenti dengan sendirinya.
  3. Baris 10 (println!("Paket masih menunggu ...", days);): nilai days yang diikat kondisi dipakai di badan perulangan tanpa pencocokan ulang.
  4. 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, kondisi while let dievaluasi lagi terhadap keadaan yang baru.
  5. Baris 19 (println!("Paket telah tiba.");): baris penutup tercapai ketika keadaan sudah tidak lagi cocok dengan pola Waiting.

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:

rust
fn main() {
    let mut count = 0;

    while let value = count {
        count += 1;
        if count >= 3 {
            break;
        }
    }

    println!("Berhenti di angka {}.", count);
}

Pesan kompilator (warning):

text
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 emitted

Program ini tetap berjalan dan menghasilkan keluaran berikut:

Output yang Dihasilkan:

text
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.