An extension function type gives a function a receiver type. Write StringBuilder.() -> Unit instead of (StringBuilder) -> Unit: the receiver moves before the parentheses, and the lambda can access its members without an explicit qualifier. section 13.2.1
Building a string with a receiver
fun buildString(builderAction: StringBuilder.() -> Unit): String { val sb = StringBuilder() sb.builderAction() return sb.toString() } val result = buildString { append("Hello, ") append("World!") } Here, sb supplies the receiver. Inside the lambda, it becomes the implicit this, so append() replaces the regular function-style call builderAction(sb). Explicit this.append(...) remains available for disambiguation. section 13.2.1
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!
}
Inspect the complete receiver-based buildString example, including its declaration, invocation, and resulting output. section 13.2.1
A receiver lambda can also be stored in a variable such as val appendExcl: StringBuilder.() -> Unit. Calling stringBuilder.appendExcl() supplies the receiver, while buildString(appendExcl) passes the same callable as a builder action. section 13.2.1
Extension function types underpin lambdas with receivers and Kotlin internal DSLs, where nested receivers make multi-call APIs more expressive and reusable. section 13.5
