不得不说,kotlin
里面提供了非常多的语法糖,尤其是 lambda
这块。
对于lambda
,有普通的,还有带接收者的。
看下面这段代码:
fun main() {
val str = buildString {
append("Hello ")
append("world !")
}
println("str = $str")
val str1 = buildStr {
it.append("hello ").append("kotlin .")
}
println("str1 = $str1")
println("buildStr1 = ${buildStr1 { it.append("hello ").append("duck @") }}")
val action: StringBuffer.() -> StringBuffer = { append("!") }
// 定义与使用 lambda 类型的变量
println("action -- ${StringBuffer("hi").action()}")
println("buildStr3 = ${buildStr3 { append("hello ").append("country #") }}")
}
/**
* 带接收者的 lambda
*/
// action: obj.() -> obj1
// String. (Int , Int) -> Unit -- 带接收者的 lambda
fun buildString(builderAction: StringBuffer.() -> StringBuffer): String {
val sb = StringBuffer()
return sb.builderAction().toString()
}
fun buildStr3(builderAction: StringBuffer.() -> Unit): String =
StringBuffer().apply { builderAction() }.toString()
/**
* 普通 lambda
*/
// action: (obj) -> obj1
fun buildStr1(builderAction: (StringBuffer) -> StringBuffer): String {
val sb = StringBuffer()
return builderAction(sb).toString()
}
fun buildStr(builderAction: (StringBuffer) -> Unit): String {
val sb = StringBuffer()
builderAction(sb)
return sb.toString()
}
代码就不解释了,注释里面做了部分说明。
看输出:
str = Hello world !
str1 = hello kotlin .
buildStr1 = hello duck @
action -- hi!
buildStr3 = hello country #
Process finished with exit code 0
对于 作为函数参数的 普通lambda
或者 带接收者的lambda
,我认为无论是定义还是调用都比较方便,也比较容易理解。
但是,对于定义的 带接收者的lambda
变量,与使用。理解起来就有点困惑了。(虽然还是可以理解)
可以看出 ,带接收者的 lambda
与扩展函数有类似的地方,就是都定义了接收者。
关于 带接收者的 lambda
:
- 作为函数参数的时候:接收者成为了这个
lambda
的实际调用者。 - 作为变量的时候:需要定义一个接收者类型的对象去调用该变量。
为什么这里是说调用变量。因为这是一个函数类型的变量。
扩展一下:调用这个变量总是无参调用吗?**不一定!**根据实际定义的lambda
来,如果定义的(带接收者的)lambda
里面定义了参数,那么在调用的时候就需要传参数进去。
总体来说,语法糖简化了表达。
不过对于StringBuffer().apply { builderAction() }.toString()
这种,总感觉各种括号堆在一块也不是很好看。而且,想要理解这句代码的话,得明白 apply
干了啥,以及自定义的builderAction
是什么。
update: 可以改成好看一点的调用格式:
fun buildStr3(builderAction: StringBuffer.() -> Unit) =
StringBuffer().apply(builderAction).toString()