Banyak pekerjaan program bersifat berulang: menghitung ulang total keranjang setiap kali barang ditambahkan, terus mendengarkan permintaan dari pengguna, atau mencoba menyambungkan kembali jaringan ketika koneksi terputus. Ciri khas pekerjaan seperti ini adalah jumlah perulangannya tidak diketahui di awal — program berhenti ketika sebuah peristiwa terjadi, bukan ketika sebuah angka tercapai. Rust menyediakan kata kunci loop untuk kebutuhan tersebut: blok kode yang dijalankan tanpa henti sampai kita secara eksplisit memutuskan untuk keluar. Pada Chapter ini kita akan mempelajari cara mengendalikan loop dengan break, termasuk kemampuan khas Rust untuk keluar dari loop sambil membawa sebuah nilai hasil.

Sintaks Dasar loop #

Kata kunci loop diikuti satu blok kurung kurawal, tanpa kondisi apa pun. Ketika eksekusi program mencapai akhir blok, Rust tidak melanjutkan ke statement setelah blok, melainkan melompat kembali ke awal blok dan mengulang isi blok dari atas. Perulangan ini benar-benar tanpa henti (infinite loop), sehingga hampir setiap loop berguna selalu berisi break — kata kunci yang menghentikan perulangan dan melanjutkan eksekusi ke statement setelah blok loop. Mari kita lihat keduanya bekerja sama:

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

    loop {
        counter += 1;
        println!("Iterasi ke-{}", counter);

        if counter == 3 {
            break;
        }
    }

    println!("Perulangan selesai.");
}

Output yang Dihasilkan:

text
Iterasi ke-1
Iterasi ke-2
Iterasi ke-3
Perulangan selesai.

Mari kita telaah apa yang terjadi pada baris-baris kode di atas:

  1. Baris 2 (let mut counter = 0;): variabel counter dibuat dengan nilai awal 0 dan ditandai mut karena nilainya akan diubah di dalam perulangan.
  2. Baris 4 (loop {): program memasuki blok perulangan tanpa henti; setelah baris terakhir blok tercapai, eksekusi kembali ke baris ini.
  3. Baris 5 (counter += 1;): nilai counter bertambah satu pada setiap iterasi — 1, 2, lalu 3.
  4. Baris 6 (println!("Iterasi ke-{}", counter);): macro println! mencetak nomor iterasi saat ini ke terminal.
  5. Baris 8 (if counter == 3 {): Rust membandingkan nilai counter dengan 3; perbandingan bernilai false pada dua iterasi pertama dan bernilai true pada iterasi ketiga.
  6. Baris 9 (break;): pada iterasi ketiga, break menghentikan perulangan seketika dan melanjutkan eksekusi ke statement setelah blok loop.
  7. Baris 13 (println!("Perulangan selesai.");): baris ini hanya tercapai setelah break dieksekusi, yang membuktikan bahwa loop telah berakhir.

Keluar dengan break Bernilai #

Kemampuan khas Rust yang jarang ada di bahasa lain: loop sebenarnya adalah sebuah expression, jadi blok loop dapat menghasilkan nilai. Nilai tersebut ditentukan oleh break yang kita beri operand — penulisan break nilai; menghentikan perulangan sekaligus menjadikan nilai sebagai hasil dari keseluruhan loop. Hasil itu lalu dapat diikat ke variabel dengan let seperti nilai expression biasa. Mari kita gunakan pola ini untuk mencari kuadrat pertama yang mencapai 100:

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

    let result = loop {
        counter += 1;

        if counter * counter >= 100 {
            break counter * counter;
        }
    };

    println!("Kuadrat pertama yang >= 100: {}", result);
}

Output yang Dihasilkan:

text
Kuadrat pertama yang >= 100: 100

Mari kita uraikan cara kerja program di atas:

  1. Baris 4 (let result = loop {): variabel result siap menampung hasil dari expression loop; program masuk ke blok perulangan untuk menghitung nilai tersebut.
  2. Baris 5 (counter += 1;): counter naik satu per satu mulai dari 1.
  3. Baris 7 (if counter * counter >= 100 {): setiap iterasi memeriksa apakah kuadrat dari counter sudah mencapai 100 — 1, 4, 9, dan seterusnya sampai 100.
  4. Baris 8 (break counter * counter;): ketika counter mencapai 10, hasil 10 * 10 adalah 100 sehingga kondisi terpenuhi; break keluar dari perulangan dan membawa nilai 100 sebagai hasil expression loop.
  5. Baris 10 (};): titik koma di sini menutup statement let result = loop ... ; — perhatikan bahwa titik koma berada setelah kurung kurawal penutup, bukan di dalam blok.
  6. Baris 12 (println!("Kuadrat pertama yang >= 100: {}", result);): nilai result yang berisi 100 dicetak ke terminal.

Perhatikan perbedaan dua bentuk break yang sudah kita temui: break; keluar tanpa membawa nilai, sedangkan break counter * counter; keluar sambil membawa nilai. Keduanya sah; bentuk kedua hanya bermakna ketika hasil loop dipakai sebagai nilai. Kita akan banyak menemui pola let result = loop { ... break nilai; }; pada Chapter-Chapter selanjutnya, misalnya saat menunggu hasil operasi yang harus dicoba berkali-kali.

Pola Percobaan Ulang Koneksi #

Kekuatan loop paling terasa ketika kondisi berhenti muncul dari dalam proses itu sendiri, bukan dari hitungan di depan. Contoh klasiknya adalah percobaan ulang koneksi: program mencoba menyambung, memeriksa hasilnya, dan mengulang selama masih gagal. Karena jumlah percobaan sebelum berhasil tidak diketahui di awal, loop dengan break bernilai bool menjadi pilihan yang pas:

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

    let connected = loop {
        attempts += 1;
        println!("Percobaan koneksi ke server, nomor {}", attempts);

        if attempts == 3 {
            break true;
        }
    };

    if connected {
        println!("Server terhubung setelah {} percobaan.", attempts);
    }
}

Output yang Dihasilkan:

text
Percobaan koneksi ke server, nomor 1
Percobaan koneksi ke server, nomor 2
Percobaan koneksi ke server, nomor 3
Server terhubung setelah 3 percobaan.

Mari kita bedah program di atas:

  1. Baris 2 (let mut attempts = 0;): variabel attempts menghitung berapa kali program sudah mencoba menyambung.
  2. Baris 4 (let connected = loop {): hasil perulangan diikat ke variabel connected; tipe connected ditentukan oleh nilai yang dibawa break, dalam contoh ini bool.
  3. Baris 5–6 (attempts += 1; dan println!(...)): setiap percobaan menaikkan penghitung lalu mencatat percobaan tersebut ke terminal.
  4. Baris 8 (if attempts == 3 {): program mensimulasikan koneksi yang berhasil pada percobaan ketiga; di program nyata, cabang ini biasanya memeriksa hasil fungsi koneksi sungguhan.
  5. Baris 9 (break true;): perulangan berakhir dan nilai true menjadi isi variabel connected.
  6. Baris 13 (if connected {): kondisi bernilai true sehingga program mencetak laporan jumlah percobaan yang memakai nilai attempts dari dalam perulangan.

Ringkasan #

Kata kunci loop menjalankan blok kode tanpa henti, dan break adalah satu-satunya jalan keluar yang kita tentukan sendiri. Rust memperlakukan loop sebagai expression, sehingga break nilai; dapat mengembalikan hasil dari perulangan dan mengikatnya ke variabel dengan let result = loop { ... };. Pola ini cocok untuk proses yang jumlah perulangannya tidak diketahui di awal seperti percobaan ulang koneksi. Selanjutnya kita akan mempelajari while, perulangan yang memeriksa kondisi sebelum setiap iterasi.