Extension lambda adalah lambda yang berperilaku seperti extension function — disimpan dalam variabel bertipe receiver function type dan dapat dipanggil pada instance receiver. Pada chapter ini kita akan melihat bagaimana extension lambda menggabungkan dua konsep: extension function (member tambahan pada tipe yang sudah ada) dan lambda (function literal yang dapat disimpan dan diteruskan). Kita juga akan melihat bagaimana pola ini menjadi dasar scope function apply dan run, serta function standard library buildString.
Apa Itu Extension Lambda #
Extension lambda adalah variabel yang bertipe receiver function type A.() -> B. Variabel ini dapat dipanggil pada instance A layaknya extension function, dan di dalam body, this merujuk ke instance receiver tersebut.
val panjang2x: String.() -> Int = { this.length * 2 }
// Pemanggilan seperti extension function:
println("Budi".panjang2x()) // 8Beda dengan extension function biasa (fun String.panjang2x(): Int { ... }), extension lambda disimpan dalam variabel dan dapat diteruskan sebagai argumen ke function lain.
Contoh Extension Lambda #
Mari kita lihat extension lambda dalam beberapa skenario — dari perhitungan sederhana hingga builder block.
// extension_lambdas.kt
// Extension lambda: kombinasi extension function dengan lambda.
// Disimpan dalam variabel bertipe receiver function type.
// Lambda dengan receiver String — di dalam body, `this` adalah String.
val panjang2x: String.() -> Int = { this.length * 2 }
// Lambda dengan receiver List<Int> untuk perhitungan.
val jumlahkan: List<Int>.() -> Int = {
var total = 0
for (e in this) total += e
total
}
// Lambda receiver yang mengembalikan String baru.
val kapitalisasi: String.() -> String = {
this.split(" ").joinToString(" ") { kata ->
kata.replaceFirstChar { it.uppercase() }
}
}
// Lambda receiver sebagai builder block.
val bangunTabel: StringBuilder.() -> Unit = {
appendLine("| Nama | Umur |")
appendLine("|-------|------|")
appendLine("| Budi | 25 |")
appendLine("| Siti | 30 |")
}
// Higher-order function yang menerima extension lambda.
inline fun <T> T.pakai(block: T.() -> Unit): T {
this.block()
return this
}
fun main() {
// Memanggil extension lambda pada instance.
println("Panjang 2x \"Budi\": ${"Budi".panjang2x()}")
val data = listOf(1, 2, 3, 4, 5)
println("Total: ${data.jumlahkan()}")
println("Kapitalisasi: ${"budi santoso".kapitalisasi()}")
// Pakai extension lambda sebagai builder.
val tabel = StringBuilder().apply { bangunTabel() }.toString()
println("Tabel:")
println(tabel)
// pakai() mengembalikan receiver setelah block dijalankan.
val hasil = "Halo".pakai {
println(" Di dalam block, this = $this")
}
println("Hasil pakai(): $hasil")
}Output yang Dihasilkan:
Panjang 2x "Budi": 8
Total: 15
Kapitalisasi: Budi Santoso
Tabel:
| Nama | Umur |
|-------|------|
| Budi | 25 |
| Siti | 30 |
Di dalam block, this = Halo
Hasil pakai(): HaloMari kita telaah baris-baris kode di atas:
- Baris 6 (
val panjang2x: String.() -> Int): variabel extension lambda bertipeString.() -> Int. Di dalam body,thisadalahStringtempat lambda dipanggil. - Baris 9 (
val jumlahkan: List<Int>.() -> Int): extension lambda dengan receiverList<Int>. Body mengiterasithis(list) dan menjumlahkan elemen. - Baris 16 (
val kapitalisasi: String.() -> String): extension lambda yang memanipulasi string. Di dalam body,thisadalahStringasli — kita memanggilthis.split(" ")untuk memecah string. - Baris 22 (
val bangunTabel: StringBuilder.() -> Unit): extension lambda sebagai builder. Body memanggilappendLinepadathis(StringBuilder) — sama seperti di dalam method classStringBuilder. - Baris 30 (
inline fun <T> T.pakai(block: T.() -> Unit): T): higher-order function yang menerima extension lambda. ReceiverTdaripakaimenjadithisdi dalamblock. Setelahblockdijalankan, function mengembalikan receiver — pola yang sama denganapply. - Baris 38 (
"Budi".panjang2x()): pemanggilan extension lambda pada instance"Budi". Sintaksnya sama dengan extension function biasa. - Baris 41 (
data.jumlahkan()): pemanggilan padaList<Int>. Lambdajumlahkanberperilaku seolah-olah adalah memberList<Int>. - Baris 47 (
val tabel = StringBuilder().apply { bangunTabel() }.toString()): menggunakanapplyuntuk menjalankan extension lambda pada instanceStringBuilder. Di dalamapply,thisadalahStringBuilder; kita kemudian memanggilthis.bangunTabel()(ekstensi lambda pada StringBuilder). - Baris 51 (
"Halo".pakai { ... }): pemanggilan functionpakaidengan trailing lambda. Di dalam block,thisadalah"Halo". Function mengembalikan"Halo"setelah block dijalankan.
Kapan Memakai Extension Lambda #
Extension lambda cocok dipakai saat kita ingin menambah perilaku pada tipe tanpa mendefinisikan ulang tipe tersebut. Pola ini sangat berguna untuk:
- Membuat DSL berbasis konfigurasi (builder block).
- Mengenkapsulasi logika yang berulang pada tipe tertentu.
- Menyediakan API yang dapat dipanggil layaknya method asli tipe tersebut.
| Aspek | Extension Function fun X.f() | Extension Lambda val f: X.() -> Y |
|---|---|---|
| Disimpan dalam variabel | Tidak | Ya |
| Bisa diteruskan sebagai argumen | Tidak langsung | Ya |
| Bisa dipanggil seperti method | Ya | Ya |
Memerlukan receiver this | Ya | Ya |
Referensi Lanjutan #
- Higher-order functions and lambdas — lambda dengan receiver — extension lambda
- Scope functions
— penerapan extension lambda pada
apply,run,with
Penutup #
Extension lambda menggabungkan kekuatan extension function dengan fleksibilitas lambda. Kita dapat menyimpan behavior tambahan untuk tipe tertentu, meneruskannya ke function lain, dan memanggilnya seperti method asli. Pola ini menjadi dasar scope function yang akan kita bahas tuntas pada chapter-chapter selanjutnya. Sebelumnya, kita perlu memahami satu konsep terkait: closure — kemampuan lambda menangkap variabel dari lingkup luar.