An implicit receiver is an object whose members can be called inside a callable body without an explicit qualifier. Kotlin gives a lambda with receiver a receiver type, making that object available as this. section 13.2.1
A StringBuilder becomes the receiver
fun buildString(builderAction: StringBuilder.() -> Unit): String { val sb = StringBuilder() sb.builderAction() return sb.toString() } val result = buildString { this.append("Hello, ") append("World!") } The lambda’s receiver is sb. Inside its body, this refers to that StringBuilder, so append("World!") needs no qualifier. section 13.2.1
The receiver can be explicit when clarity matters. apply and with invoke a receiver lambda on an object; apply returns the receiver, while with returns the lambda result. section 13.2.1
Implicit receivers support practical Kotlin DSL patterns:
- HTML builders nest tag-specific receivers, allowing table, tr, and td calls to read like the structure they generate. section 13.2.2
- Multiple nested receivers can make an unqualified property ambiguous; this@table and this@tr make the intended receiver explicit. section 13.2.2
- @DslMarker restricts outer receivers with the same marker, preventing accidental access inside nested DSL blocks. section 13.2.2
- Gradle-style dependency blocks use DependencyHandler as an implicit receiver, so implementation can be called directly. section 13.3.2
Listing 13.2 Redefining buildString to take a lambda with a receiver
fun buildString(
builderAction: StringBuilder.() -> Unit #1
): String {
val sb = StringBuilder()
sb.builderAction() #2
return sb.toString()
}
fun main() {
val s = buildString {
this.append("Hello, ") #3
append("World!") #4
}
println(s)
// Hello, World!
}
Compare an ordinary lambda taking StringBuilder explicitly with a lambda whose StringBuilder receiver makes member calls unqualified. section 13.2.1
