Lambda pada bab-bab sebelumnya memakai variabel yang bukan parameternya, seperti minimalGratisOngkir. Bagaimana sebuah fungsi kecil dapat mengingat variabel di luar dirinya? Jawabannya adalah closure: compiler membungkus variabel yang ditangkap ke dalam satu objek, dan lambda mengaksesnya lewat objek tersebut, bukan lewat salinan nilainya.
Istilah “menutup” (closing over) merujuk pada lambda yang menutup dirinya di atas variabel luar. Implementasinya mekanis: compiler membuat satu class pembungkus yang menampung variabel yang ditangkap, lalu seluruh lambda yang menutup atas variabel yang sama berbagi objek pembungkus itu. Itulah sebabnya dua lambda yang menangkap variabel yang sama saling melihat perubahan satu sama lain. Konsep ini penting dipahami sebelum masuk ke contoh, karena kedua perilaku di bawah berangkat dari aturan yang sama.
Menangkap Variabel, Bukan Nilai #
int kupon = 10000;
Func<int, int> hitungBayar = total => total - kupon;
Console.WriteLine(hitungBayar(50000));
kupon = 25000;
Console.WriteLine(hitungBayar(50000));
Func<int> penghitung = BuatPenghitung();
penghitung();
penghitung();
Console.WriteLine(penghitung());
static Func<int> BuatPenghitung()
{
int hitungan = 0;
return () => ++hitungan;
}Output yang Dihasilkan:
40000
25000
3Bedah Kode Baris per Baris #
Mari kita telaah kode di atas:
- Baris 3: Lambda
hitungBayarmenangkap variabelkupon. Yang ditangkap adalah variabelnya, bukan nilai10000saat itu. - Baris 5-8: Perubahan
kuponmenjadi25000langsung terasa pada pemanggilan berikutnya: hasil turun dari40000menjadi25000. Bukti ini menegaskan semantik by reference. - Baris 10-13:
BuatPenghitungmendeklarasikanhitunganlalu mengembalikan lambda yang menaikannya. Setelah method selesai, variabelhitungantetap hidup karena lambda memegangnya. - Baris 11-13: Tiga pemanggilan
penghitung()menghasilkan1,2, dan3; dua panggilan pertama tanpa pencetakan, dan panggilan ketiga mencetak3.
Contoh penghitung adalah pola stateful yang sah: closure memberi lambda memori antar panggilan tanpa perlu field class. Namun kebiasaan yang sama menjadi sumber bug bila variabel yang ditangkap berubah tanpa sengaja; bab Variable Capture menunjukkan kasus loop-nya.