Receiver function type adalah bentuk khusus function type di mana lambda memiliki receiver — sebuah objek yang menjadi this di dalam body lambda. Sintaksnya ditulis A.() -> B dan dibaca “function dengan receiver A yang mengembalikan B”. Pada chapter ini kita akan memahami cara kerja receiver function type, bagaimana this otomatis terikat ke receiver, dan mengapa pola ini menjadi dasar DSL Kotlin seperti buildString, apply, dan HTML builder. Kita juga akan membandingkan receiver function type dengan lambda biasa yang menerima receiver sebagai parameter eksplisit.
Apa Itu Receiver Function Type #
Receiver function type memiliki bentuk ReceiverType.() -> ReturnType. Di dalam body lambda, this otomatis merujuk ke instance receiver. Kita dapat memanggil member receiver tanpa prefix this. (sama seperti di dalam method class).
// Lambda biasa: parameter eksplisit
val a: (String) -> String = { s -> "Halo, $s!" }
// Receiver function type: `this` adalah String
val b: String.() -> String = { "Halo, $this!" }
// Pemanggilan:
a("Budi") // parameter biasa
"Budi".b() // dipanggil pada receiverContoh Receiver Function Type #
Mari kita lihat penerapan receiver function type dalam beberapa skenario nyata.
// receiver_function_types.kt
// Function type dengan receiver: Int.() -> String.
// Di dalam lambda, `this` adalah receiver.
// Lambda dengan receiver — di dalam body, `this` adalah String.
val pesanHalo: String.() -> String = {
"Halo, $this! Panjang nama ${this.length} karakter."
}
// Receiver type dengan parameter tambahan.
val ulang: String.(Int) -> String = { n ->
this.repeat(n)
}
// Higher-order function yang menerima receiver lambda.
// Receiver adalah StringBuilder sehingga `this` di dalam block adalah StringBuilder.
fun bangunHtml(block: StringBuilder.() -> Unit): String {
val sb = StringBuilder("<html>")
sb.block()
sb.append("</html>")
return sb.toString()
}
// Function yang menerima receiver lambda untuk konfigurasi.
fun konfigurasiPesan(block: StringBuilder.() -> Unit): String {
val sb = StringBuilder("PESAN: ")
sb.block()
return sb.toString()
}
fun main() {
// Memanggil receiver lambda langsung pada instance.
val hasil = "Budi".pesanHalo()
println(hasil)
// Memanggil dengan parameter tambahan.
val ulangan = "Ha".ulang(3)
println("Ulang: $ulangan")
// Memakai bangunHtml — `this` di dalam block adalah StringBuilder.
val html = bangunHtml {
append("<head><title>Halo</title></head>")
append("<body>Selamat datang</body>")
}
println("HTML: $html")
// Memakai konfigurasiPesan.
val pesan = konfigurasiPesan {
append("Belajar Kotlin ")
append("di tahun 2026")
}
println(pesan)
// Receiver lambda vs lambda biasa.
val lambdaBiasa: (String) -> String = { s -> "Halo, $s!" }
val lambdaReceiver: String.() -> String = { "Halo, $this!" }
println("Lambda biasa: ${lambdaBiasa("Budi")}")
println("Lambda receiver: ${"Budi".lambdaReceiver()}")
}Output yang Dihasilkan:
Halo, Budi! Panjang nama 4 karakter.
Ulang: HaHaHa
HTML: <html><head><title>Halo</title></head><body>Selamat datang</body></html>
PESAN: Belajar Kotlin di tahun 2026
Lambda biasa: Halo, Budi!
Lambda receiver: Halo, Budi!Mari kita telaah baris-baris kode di atas:
- Baris 6 (
val pesanHalo: String.() -> String): receiver function type dengan receiverString. Di dalam body,thismerujuk ke instanceStringyang menjadi receiver. - Baris 7 (
"Halo, $this! Panjang nama ${this.length} karakter."): pemanggilanthisdi dalam body mengakses receiverString. Kita bisa pakaithiseksplisit atau memanggil member tanpa prefix. - Baris 11 (
val ulang: String.(Int) -> String): receiver function type dengan satu parameter tambahan. Di dalam body,thisadalahStringdannadalah parameterInt. Body memanggilthis.repeat(n). - Baris 16 (
fun bangunHtml(block: StringBuilder.() -> Unit)): higher-order function yang menerima receiver lambda. ParameterblockbertipeStringBuilder.() -> Unit, sehingga di dalam bodyblock,thisadalahStringBuilder. - Baris 17-21: implementasi membuat
StringBuilder, memanggilblockpada sb sehinggaappenddi dalamblockmenambah kesb, lalu mengembalikan hasiltoString(). - Baris 32 (
val hasil = "Budi".pesanHalo()): pemanggilan receiver lambda langsung pada instance"Budi". String"Budi"menjadithisdi dalam lambda. - Baris 36 (
"Ha".ulang(3)): pemanggilan receiver lambda dengan argumen parameter tambahan3. Hasilnya"HaHaHa". - Baris 39-43 (
bangunHtml { append(...) }): pemanggilan dengan trailing lambda. Di dalam block,appendmerujuk ke methodStringBuilder.appendtanpa prefixthis.— persis seperti di dalam method class. - Baris 53-55: perbandingan langsung antara lambda biasa
(String) -> Stringdan receiver lambdaString.() -> String. Keduanya menghasilkan output yang sama, tetapi cara pemanggilan berbeda.
Perbandingan Lambda Biasa vs Receiver Lambda #
| Aspek | Lambda Biasa (A) -> B | Receiver Lambda A.() -> B |
|---|---|---|
| Parameter | Eksplisit a -> ... | Implisit this |
| Pemanggilan member | a.foo() | foo() atau this.foo() |
| Cara panggil | lambda(a) | a.lambda() atau a.lambda() via extension |
| Konteks idiomatik | Transformasi | DSL, builder, scope function |
Mengapa Receiver Function Type Penting #
Receiver function type memungkinkan kita menulis DSL yang terbaca seperti blok konfigurasi alami. Standard library Kotlin memanfaatkan pola ini di banyak tempat:
buildString { append(...) }—thisadalahStringBuilder.apply { ... }—thisadalah objek yang dikonfigurasi.with(obj) { ... }—thisadalahobj.run { ... }—thisadalah receiver.
Tanpa receiver function type, kode DSL akan terlihat berantakan dengan prefix eksplisit di setiap baris.
Referensi Lanjutan #
- Higher-order functions and lambdas
— panduan function type with receiver
A.(B) -> R - Scope functions
— receiver type sebagai dasar
applydanrun
Penutup #
Receiver function type adalah kunci yang membuat Kotlin cocok untuk membangun DSL. Dengan this otomatis terikat ke receiver, kode di dalam block terbaca seperti method class — ringkas dan terfokus. Selanjutnya, kita akan melihat bagaimana receiver function type dipadukan dengan konsep extension function menjadi extension lambda yang dapat disimpan dalam variabel dan dipanggil pada instance kapan saja.