Perulangan (loop) menjalankan blok kode yang sama berkali-kali. Rust punya tiga bentuk: loop, while, dan for. Bayangin dapur Kedai Martabak Bang Rusdi waktu ramai. Koki membuat martabak telur satu demi satu, dan langkahnya selalu sama: pecahkan 3 telur, adon, goreng. Yang beda cuma cara dia tahu kapan berhenti. "Terus bikin sampai aku bilang stop" itu loop. "Bikin selama telurnya masih cukup" itu while. "Bikin satu untuk tiap meja, meja 1 sampai 3" itu for.
🧪 Tebakan cepat: Bang Rusdi ingin mencetak tiga baris porsi dengan
for porsi in 1..3 { println!("Porsi ke-{}", porsi); }. Berapa baris yang tercetak? Tebak dulu, jawabannya ada di bagian "for dan range".
loop: ulangi sampai break
Berapa martabak telur yang bisa dibuat dari stok 250 butir, kalau satu martabak memakai 3 butir?
fn main() {
let mut stok_telur: u32 = 250;
let mut jumlah = 0;
let dibuat = loop {
if stok_telur < 3 {
break jumlah;
}
stok_telur -= 3;
jumlah += 1;
};
println!("Martabak telur dibuat: {}", dibuat);
println!("Sisa telur: {}", stok_telur);
}
Martabak telur dibuat: 83
Sisa telur: 1
loop { ... }mengulang isinya terus, tanpa syarat apa pun. Satu-satunya jalan keluar adalahbreak.break jumlah;keluar dari loop sambil membawa nilai, jadilet dibuat = loop { ... };menyimpan nilai itu. Miripifsebagai expression, makanya ada titik koma setelah}penutup.- 83 martabak memakai 83 × 3 = 249 butir, jadi sisa 1 butir, dan 1 gak cukup untuk martabak berikutnya.
- Lupa
breakberarti program gak pernah selesai. Hentikan dengan Ctrl+C di terminal. while true { }juga jalan, tapi compiler memberi warningdenote infinite loops with `loop { ... }`. Untuk loop tanpa syarat, pakailoop.
while: selama kondisinya benar
Sekarang stoknya cuma 10 butir, dan tiap pesanan dicetak:
fn main() {
let mut stok_telur = 10;
let mut pesanan = 0;
while stok_telur >= 3 {
stok_telur -= 3;
pesanan += 1;
println!("Pesanan {}: sisa telur {}", pesanan, stok_telur);
}
println!("Sisa telur: {}", stok_telur);
}
Pesanan 1: sisa telur 7
Pesanan 2: sisa telur 4
Pesanan 3: sisa telur 1
Sisa telur: 1
| Putaran | Cek stok_telur >= 3 |
stok_telur sesudahnya |
pesanan |
|---|---|---|---|
| 1 | 10 >= 3, benar | 7 | 1 |
| 2 | 7 >= 3, benar | 4 | 2 |
| 3 | 4 >= 3, benar | 1 | 3 |
| 4 | 1 >= 3, salah: berhenti | 1 | 3 |
- Kondisi dicek sebelum tiap putaran. Begitu salah, Rust lanjut ke baris setelah
}. Kondisinya wajibbool, sama sepertiif. - Variabel yang dicek harus berubah di dalam loop. Tanpa
stok_telur -= 3;, kondisinya benar terus dan loop gak pernah berhenti. pesanan += 1;menambah 1. Rust gak punya++. Kalau kamu menulispesanan++;seperti di JavaScript:
error: Rust has no postfix increment operator
--> src/main.rs:6:16
|
6 | pesanan++;
| ^^ not a valid postfix operator
|
help: use `+= 1` instead
|
6 - pesanan++;
6 + pesanan += 1;
|
for dan range
fn main() {
for porsi in 1..=3 {
println!("Porsi ke-{}", porsi);
}
for porsi in 1..3 {
println!("Porsi ke-{}", porsi);
}
}
Porsi ke-1
Porsi ke-2
Porsi ke-3
Porsi ke-1
Porsi ke-2
1..=3adalah range (deretan angka) yang termasuk ujungnya: 1, 2, 3.1..3berhenti sebelum ujungnya: 1, 2. Itu jawaban tebakannya: cuma dua baris. Begitu juga0..3jalan tiga kali (0, 1, 2), dan angka terakhirnya 2.porsidibuat baru di tiap putaran, jadi gak perluletataumut. Di dalam loop ia dipakai seperti variabel biasa, misalnyaporsi % 2 == 0(sisa bagi 2 nol: genap).- Pakai
forkalau banyaknya putaran sudah jelas sejak awal. Gak ada penghitung yang bisa lupa ditambah.
for di atas array: nilai atau pinjaman
for juga bisa mengambil isi array satu per satu:
fn main() {
let harga = [32000, 38000, 5000];
let mut total = 0;
for h in harga {
total += h;
}
println!("Total: {}", total);
for (i, h) in harga.iter().enumerate() {
println!("{}: {}", i, h);
}
}
Total: 75000
0: 32000
1: 38000
2: 5000
.iter().enumerate() memberi pasangan (nomor urut, isi), mulai dari 0. Untuk angka, for h in harga aman dipakai berulang, karena tiap angka disalin. Teks String beda: ia dipindah, seperti nota pesanan yang pindah ke dapur di pelajaran pertama.
fn main() {
let antrean = [String::from("Martabak manis"), String::from("Martabak telur")];
for pesanan in antrean {
println!("Dimasak: {}", pesanan);
}
println!("Antrean: {}", antrean.len());
}
error[E0382]: borrow of moved value: `antrean`
--> src/main.rs:6:29
|
2 | let antrean = [String::from("Martabak manis"), String::from("Martabak telur")];
| ------- move occurs because `antrean` has type `[String; 2]`, which does not implement the `Copy` trait
3 | for pesanan in antrean {
| ------- `antrean` moved due to this implicit call to `.into_iter()`
...
6 | println!("Antrean: {}", antrean.len());
| ^^^^^^^ value borrowed here after move
|
help: consider iterating over a slice of the `[String; 2]`'s content to avoid moving into the `for` loop
|
3 | for pesanan in &antrean {
| +
for pesanan in antrean memindahkan tiap nota ke pesanan, jadi setelah loop antrean sudah kosong. Saran compiler-nya tepat: for pesanan in &antrean cuma meminjam tiap nota. Dengan &, programnya mencetak Dimasak: Martabak manis, Dimasak: Martabak telur, lalu Antrean: 2.
break, continue, dan label
continue melompati sisa putaran ini dan lanjut ke putaran berikutnya. for meja in 1..=5 dengan if meja == 3 { continue; } mengantar ke meja 1, 2, 4, 5.
Loop di dalam loop butuh hati-hati: break biasa cuma keluar dari loop terdalam. Untuk keluar dari semuanya sekaligus, beri loop luar sebuah label:
fn main() {
let mut stok_telur = 7;
'pesanan: for meja in 1..=3 {
for porsi in 1..=2 {
if stok_telur < 3 {
println!("Telur habis di meja {} porsi {}", meja, porsi);
break 'pesanan;
}
stok_telur -= 3;
println!("Meja {} porsi {}: sisa telur {}", meja, porsi, stok_telur);
}
}
}
Meja 1 porsi 1: sisa telur 4
Meja 1 porsi 2: sisa telur 1
Telur habis di meja 2 porsi 1
- Label ditulis dengan kutip tunggal di depan dan titik dua di belakang:
'pesanan:.break 'pesanan;keluar dari loop bernama itu. - Tanpa label,
break;cuma menghentikanfor porsi, lalu loop meja lanjut ke meja 3 dan mencetak satu baris lagi:Telur habis di meja 3 porsi 1.
⚠️ Jebakan yang sering ketemu
- Range kurang satu.
1..15berhenti di 14. Untuk 1 sampai 15, tulis1..=15. - Menulis
i++. Rust gak punya++dan--. Pakaii += 1dani -= 1. - while yang gak pernah berhenti. Variabel di kondisinya harus berubah di dalam loop.
- Array String habis dipindah.
for x in antreanmemindahkan isinya. Pakaifor x in &antreankalau array-nya masih dipakai. - Urutan cek kelipatan. 15 habis dibagi 3 dan 5, jadi di FizzBuzz cek
i % 15 == 0paling atas. Kalaui % 3 == 0duluan, 15 tercetakFizz.
TL;DR: loop mengulang terus sampai break, dan break nilai; membuat loop menghasilkan nilai (let dibuat = loop { ... };). while kondisi { } mengecek kondisi bool sebelum tiap putaran, jadi variabelnya harus berubah di dalam. for x in 1..=3 termasuk 3, for x in 1..3 berhenti di 2 (0..3 jalan tiga kali). for h in harga mengambil isi array, tapi untuk String isinya dipindah: pakai &antrean untuk meminjam. continue melompati satu putaran, break keluar dari loop terdalam, dan break 'label; keluar dari loop yang diberi label. Rust gak punya ++: tulis += 1.