Iterator di Rust
Iterator (penghasil nilai berurutan) adalah apa saja yang bisa menghasilkan serangkaian nilai, satu per satu. Kamu sebenarnya sudah memakainya sejak halaman For, meski mungkin belum tahu namanya: setiap perulangan for atas sebuah koleksi dijalankan oleh iterator di balik layar.
Mendapatkan iterator
Section titled “Mendapatkan iterator”fn main() { let numbers = vec![1, 2, 3]; let mut iter = numbers.iter();
println!("{:?}", iter.next()); // Some(1) println!("{:?}", iter.next()); // Some(2) println!("{:?}", iter.next()); // Some(3) println!("{:?}", iter.next()); // None}Output:
Some(1)Some(2)Some(3)None.next() mengembalikan sebuah Option: Some(value) untuk setiap item, dan None setelah item-nya habis. Perulangan for sebenarnya hanya memanggil .next() berulang kali di balik layar sampai mendapat None.
map: mengubah setiap item
Section titled “map: mengubah setiap item”.map() menerima sebuah closure dan menerapkannya pada setiap item, sehingga menghasilkan iterator baru:
fn main() { let numbers = vec![1, 2, 3, 4, 5]; let doubled: Vec<i32> = numbers.iter().map(|n| n * 2).collect();
println!("{:?}", doubled);}Output:
[2, 4, 6, 8, 10].collect() adalah yang mengubah iterator kembali menjadi koleksi yang nyata (di sini, Vec<i32>). Tanpanya, kamu hanya punya iterator yang belum dijalankan sama sekali.
filter: menyimpan sebagian item saja
Section titled “filter: menyimpan sebagian item saja”fn main() { let numbers = vec![1, 2, 3, 4, 5, 6]; let evens: Vec<&i32> = numbers.iter().filter(|n| **n % 2 == 0).collect();
println!("{:?}", evens);}Output:
[2, 4, 6]**n yang dobel itu memang terlihat aneh. .filter() memberi closure sebuah referensi ke referensi (&&i32), jadi perlu di-dereference dua kali supaya bisa dibandingkan dengan angka biasa. Ini keanehan kecil yang sering muncul; tidak perlu memikirkan penjelasan lengkapnya sekarang.
Merangkai map dan filter
Section titled “Merangkai map dan filter”Di sinilah merangkai (chaining) method iterator mulai terasa manfaatnya: kamu bisa menggabungkan beberapa langkah menjadi satu alur yang mudah dibaca:
fn main() { let numbers = vec![1, 2, 3, 4, 5, 6];
let result: Vec<i32> = numbers .iter() .filter(|n| **n % 2 == 0) // simpan bilangan genap .map(|n| n * 10) // kalikan masing-masing dengan 10 .collect();
println!("{:?}", result);}Output:
[20, 40, 60]Bandingkan dengan menulis logika yang sama memakai perulangan for manual dan Vec kosong yang kamu isi dengan push. Cara itu tidak salah, tapi versi berantai terbaca lebih mirip “saring, lalu kalikan, lalu kumpulkan”, persis urutan langkah yang ingin kamu jelaskan.
Beberapa method lain yang sering dipakai
Section titled “Beberapa method lain yang sering dipakai”fn main() { let numbers = vec![1, 2, 3, 4, 5];
let total: i32 = numbers.iter().sum(); let count = numbers.iter().count(); let has_even = numbers.iter().any(|n| n % 2 == 0);
println!("jumlah: {total}, banyaknya: {count}, ada yang genap: {has_even}");}Output:
jumlah: 15, banyaknya: 5, ada yang genap: true.sum() menjumlahkan semuanya, .count() memberi tahu berapa banyak item yang ada, dan .any() menjawab “apakah ada setidaknya satu item yang cocok?”. Ini baru sebagian kecil method yang dimiliki setiap iterator. Masih banyak lagi, seperti enumerate, zip, take, dan rev. Di halaman Iterator kustom, kamu akan membuat iterator sendiri dan melihat bahwa ia mendapat semua method ini secara gratis.
Latihan
Section titled “Latihan”1. Jumlah kuadrat bilangan ganjil
Section titled “1. Jumlah kuadrat bilangan ganjil”Ambil angka 1 sampai 10, simpan yang ganjil saja, kuadratkan masing-masing, lalu jumlahkan semuanya. Lakukan dalam satu rangkaian iterator, tanpa variabel mut. Petunjuk: rangkai .filter(), .map(), dan .sum(), lalu beri hasilnya tipe seperti let total: i32.
Lihat solusi
fn main() { let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let total: i32 = numbers .iter() .filter(|n| **n % 2 == 1) // simpan 1, 3, 5, 7, 9 .map(|n| n * n) // 1, 9, 25, 49, 81 .sum();
println!("jumlah kuadrat bilangan ganjil: {total}");}Output:
jumlah kuadrat bilangan ganjil: 165Rust butuh : i32 pada total karena .sum() bisa menjumlahkan ke beberapa tipe angka, dan Rust tidak bisa menebak tipe mana yang kamu mau.
2. Teriakkan kata-kata yang panjang
Section titled “2. Teriakkan kata-kata yang panjang”Mulai dari vec!["the", "quick", "brown", "fox", "jumps"]. Buat Vec<String> baru yang hanya berisi kata yang panjangnya lebih dari 3 huruf, dalam huruf kapital, lalu cetak dengan {:?}. Petunjuk: .filter(|w| w.len() > 3) menyimpan kata-kata yang panjang, dan .to_uppercase() mengubah &str menjadi String berhuruf kapital.
Kata-katanya sengaja dibiarkan dalam bahasa Inggris: hasilnya bergantung pada panjang setiap kata, jadi kalau diterjemahkan, output-nya akan berubah.
Lihat solusi
fn main() { let words = vec!["the", "quick", "brown", "fox", "jumps"];
let loud: Vec<String> = words .iter() .filter(|w| w.len() > 3) .map(|w| w.to_uppercase()) .collect();
println!("{:?}", loud);}Output:
["QUICK", "BROWN", "JUMPS"]words sendiri tidak berubah. .iter() hanya meminjamnya, jadi kamu masih bisa memakai words setelah rangkaian itu.
Ringkasan
Section titled “Ringkasan”- Iterator menghasilkan nilai satu per satu lewat
.next(), yang mengembalikanOption. - Perulangan
forsebenarnya adalah iterator di balik layar. .map()mengubah setiap item;.filter()hanya menyimpan item yang memenuhi syarat;.collect()mengubah hasilnya kembali menjadi koleksi yang nyata.- Merangkai method iterator biasanya lebih jelas daripada perulangan manual dengan variabel penampung yang mutable.
Kuis singkat
Section titled “Kuis singkat”Kuis singkat
1. Apa yang dikembalikan .next() pada sebuah iterator?
2. Apa fungsi .collect() di akhir rangkaian seperti .iter().map(...).collect()?
3. Pada .filter(|n| **n % 2 == 0), kenapa n di-dereference dua kali?
4. Apa yang menjalankan perulangan for saat ia melewati sebuah koleksi?
5. Apa yang disimpan .filter() di iterator hasilnya?
Skor: 0 / 5
Bacaan lebih lanjut
Section titled “Bacaan lebih lanjut”- Processing a Series of Items with Iterators — The Rust Book (bahasa Inggris): pengenalan resmi tentang
next,map,filter, dancollect, dengan contoh tambahan. - Comparing Performance: Loops vs. Iterators — The Rust Book (bahasa Inggris): kenapa rangkaian iterator sama cepatnya dengan perulangan yang ditulis manual.
Iteratortrait — standard library docs (bahasa Inggris): daftar lengkap method iterator, masing-masing dengan contoh kecil. Asyik untuk dijelajahi.- Iterators — Rust by Example (bahasa Inggris): contoh singkat yang bisa dijalankan, membuat iterator Fibonacci.