Higher-Order Function
Fungsi yang menerima atau mengembalikan fungsi lain: callback dan strategi.
Fungsi sebagai warga kelas satu
Di Dart, fungsi bukan warga kelas dua: ia bisa disimpan di variabel, dioper sebagai argumen, dan dikembalikan dari fungsi lain. Fungsi yang melakukan salah satu dari itu disebut higher-order function.
Analogi: resep masakan biasanya tetap, tapi kamu bisa mengganti "bumbu"nya. Higher-order function adalah resep yang bumbunya (perilaku) bisa diganti-ganti lewat parameter fungsi.
Kenapa higher-order function ada?
Karena ia memisahkan kerangka dari detail. Contoh: fungsi prosesData tahu cara loop dan validasi, tapi "apa yang dilakukan per item" diserahkan ke fungsi parameter. Satu kerangka, tak terbatas variasi perilaku, tanpa duplikasi.
Fungsi sebagai parameter (callback)
// Menerima fungsi sebagai parameter
void proses(int a, int b, int Function(int, int) operasi) {
var hasil = operasi(a, b);
print('Hasil: $hasil');
}
int tambah(int x, int y) => x + y;
int kali(int x, int y) => x * y;
void main() {
proses(6, 3, tambah); // Hasil: 9
proses(6, 3, kali); // Hasil: 18
proses(6, 3, (x, y) => x - y); // Hasil: 3, anonim langsung
}Tipe int Function(int, int) dibaca: "fungsi yang menerima dua int dan mengembalikan int". Satu fungsi proses, tiga perilaku berbeda.
Contoh kedua, pola yang sangat umum: eksekusi dengan retry:
Future<T> denganRetry<T>(Future<T> Function() aksi, {int maks = 3}) async {
for (int i = 1; i <= maks; i++) {
try {
return await aksi();
} catch (e) {
print('Percobaan $i gagal: $e');
if (i == maks) rethrow;
}
}
throw StateError('tidak tercapai');
}
Future<String> ambilData() async {
await Future.delayed(Duration(milliseconds: 100));
return 'OK';
}
Future<void> main() async {
var hasil = await denganRetry(ambilData);
print(hasil);
}denganRetry tidak tahu apa aksinya; ia hanya tahu "coba sampai 3 kali". Logika retry ditulis sekali, dipakai untuk semua operasi async.
Fungsi yang mengembalikan fungsi
// Membuat fungsi baru dengan "pengali" terkunci
int Function(int) buatPengali(int faktor) {
return (int n) => n * faktor;
}
void main() {
var kaliDua = buatPengali(2);
var kaliSepuluh = buatPengali(10);
print(kaliDua(5)); // 10
print(kaliSepuluh(5)); // 50
}buatPengali(2) menghasilkan fungsi baru yang "mengingat" faktor 2. Ini disebut currying parsial, berguna untuk membuat varian fungsi terkonfigurasi.
Kesalahan umum
1. Lupa tanda kurung saat mengoper fungsi
// SALAH: tambah() langsung DIEKSEKUSI, hasilnya yang dioper
void main() {
// proses(6, 3, tambah(?, ?)); // tidak masuk akal
}// BENAR: tanpa kurung = oper fungsinya sendiri
void main() {
proses(6, 3, tambah);
}tambah = fungsinya, tambah(1, 2) = hasilnya. Untuk callback, oper tanpa kurung.
2. Tipe fungsi tidak cocok
// SALAH
void proses(int Function(int, int) op) {}
// proses((x) => x * 2); // ERROR: butuh 2 parameter// BENAR
void main() {
proses((x, y) => x * y);
}
void proses(int Function(int, int) op) {
print(op(3, 4));
}3. Typedef untuk tipe fungsi panjang
// Melelahkan jika diulang
// void daftar(void Function(String, int, bool) cb) {}
// BENAR: beri nama dengan typedef
typedef CallbackUser = void Function(String nama, int umur, bool aktif);
void daftar(CallbackUser cb) {
cb('Budi', 17, true);
}
void main() {
daftar((nama, umur, aktif) => print('$nama, $umur, $aktif'));
}Kesimpulan
Higher-order function = fungsi yang memakai fungsi lain sebagai parameter atau return value. Pola ini memisahkan kerangka dari detail, menghasilkan kode reusable: callback, retry, strategi. Kuasai ini dan kamu membaca kode Flutter modern dengan lancar.
Catatan teknis: Method collection seperti
.map(),.where(),.forEach()adalah higher-order function bawaan. Setiap kali memakainya, kamu sudah mempraktikkan konsep ini.
Tantangan
Filter generik
Buat higher-order function saring(List<int> data, bool Function(int) syarat) yang mengembalikan list berisi elemen yang memenuhi syarat. Uji dengan syarat genap dan syarat > 10.
List<int> saring(List<int> data, bool Function(int) syarat) {
// TODO
return [];
}
void main() {
var angka = [5, 12, 8, 20, 3];
// TODO: uji dengan (n) => n % 2 == 0 dan (n) => n > 10
}