Halo teman-teman semuanya, pada artikel sebelumnya kita sudah mempelajari tentang iterator di Rust. Kita melihat bagaimana iterator bisa digunakan untuk mengakses, memproses, dan memanipulasi data dalam collection dengan cara yang elegan dan efisien. Iterator sangat powerful, apalagi ketika digabungkan dengan fitur Rust lain yaitu closure.
Closure adalah fungsi anonim (tanpa nama) yang bisa disimpan dalam variabel atau dipanggil langsung. Closure mirip dengan fungsi biasa, tetapi lebih fleksibel karena bisa menangkap variabel dari lingkup (scope) tempat closure dibuat. Inilah yang membuat closure sering digunakan bersama iterator untuk operasi seperti .map()
, .filter()
, dan sebagainya.
Mari kita bahas satu per satu.
Closure Sederhana
Closure ditulis dengan tanda | |
untuk parameter, diikuti dengan isi blok.
fn main() {
let tambah = |a: i32, b: i32| -> i32 { a + b };
println!("Hasil: {}", tambah(2, 3));
}
Di sini kita membuat closure tambah
yang menerima dua parameter dan mengembalikan hasil penjumlahan. Closure disimpan dalam variabel seperti nilai biasa.
Closure dengan Type Inference
Rust bisa menebak tipe parameter dan return value dari closure secara otomatis, jadi kita tidak selalu perlu menuliskan tipe secara eksplisit.
fn main() {
let kali = |x, y| x * y;
println!("3 * 4 = {}", kali(3, 4));
}
Rust akan menganggap parameter x
dan y
sebagai i32
jika pertama kali closure dipanggil dengan angka.
Closure Menangkap Variabel dari Scope
Closure bisa menggunakan variabel yang ada di lingkup luar tempat closure dibuat.
fn main() {
let factor = 10;
let multiply = |x| x * factor;
println!("5 * 10 = {}", multiply(5));
}
Closure multiply
menangkap variabel factor
dari lingkup luar tanpa perlu mengirimkannya sebagai parameter.
Closure Bersama Iterator
Closure paling sering digunakan bersama iterator, misalnya untuk transformasi data dengan .map()
atau filter data dengan .filter()
.
fn main() {
let angka = vec![1, 2, 3, 4, 5];
let hasil: Vec<i32> = angka.iter()
.map(|x| x * 2) // closure untuk menggandakan nilai
.filter(|x| x > &5) // closure untuk menyaring nilai > 5
.collect();
println!("Hasil: {:?}", hasil);
}
Output:
Hasil: [6, 8, 10]
Closure di sini membuat kode menjadi lebih ringkas dan ekspresif.
Closure dengan Return Value Kompleks
Closure juga bisa mengembalikan tipe data kompleks seperti struct atau tuple.
fn main() {
let pair = |a, b| (a, b);
let hasil = pair(1, "Rust");
println!("Pair: {:?}", hasil);
}
Menyimpan Closure dalam Variabel
Kita bisa menyimpan closure ke dalam variabel, bahkan membuat array atau vector berisi closure.
fn main() {
let tambah_satu = |x| x + 1;
let kali_dua = |x| x * 2;
println!("5 + 1 = {}", tambah_satu(5));
println!("5 * 2 = {}", kali_dua(5));
}
Kesimpulan
Pada artikel ini kita sudah mempelajari tentang closure di Rust. Kita melihat bagaimana closure dibuat, bagaimana Rust melakukan type inference, bagaimana closure bisa menangkap variabel dari scope luar, dan bagaimana closure sering dipakai bersama iterator untuk membuat kode yang lebih ringkas dan ekspresif.
Closure adalah salah satu fitur penting di Rust yang membuat pemrograman fungsional terasa alami, terutama saat bekerja dengan collection.
Pada artikel berikutnya, kita akan membahas tentang Concurrency di Rust, yaitu bagaimana menjalankan beberapa tugas secara bersamaan dengan thread, channel, dan async/await.
Terima Kasih