一、概述
在看一些开源,或者他人的代码的时候遇到这种语法。高级函数参数里有个 类名.(),曾经也抄过放到自己的代码里。但是没有深究,一段时间后看的时候又忘记是什么意思了,so 记录一下。
二、先说结论
className.() 在高阶函数中出现,作为高阶函数的一个参数。
表示:一个以className 对象作为参数的函数或者Lambda
fun className.()
//表示的是
fun xxx(ob:className){
}
//或者
{ ob:className->
}
细节this表示见下文。
三、出现过的场景
fun ViewModel.launch(
block: suspend CoroutineScope.() -> Unit,
fail: (t: Throwable) -> Unit = { },
toastNetWorkError: Boolean = GLOBAL_TOAST_NETWORK_ERROR,
toastResponseError: Boolean = GLOBAL_TOAST_RESPONSE_ERROR
) = viewModelScope.safeLaunch(block, fail, toastNetWorkError, toastResponseError)
fun TextView.addTextChangedListenerDsl(init: TextWatcherDslImpl.() -> Unit) {
val listener = TextWatcherDslImpl()
listener.init()
this.addTextChangedListener(listener)
}
三、错误的理解
错误1:一开始和小伙伴讨论,以为是className.()表示的是className的扩展函数,来做参数。后面仔细想了下,写了个demo验证是不对的。和扩展函数没啥关系。
四、验证demo
class A {
fun xx() {
}
}
fun zz(s: A): Unit {
println("zz s=$s")
}
fun String.addFun(action: A.() -> Unit) {
val a = A()
println("addFun a=$a")
a.action()
}
fun String.addFun2(action: (A) -> Unit) {
val a = A()
println("addFun2 a=$a")
action(a)
}
fun main(args: Array<String>) {
val demo = ""
//第一种
val f1 = { a: A ->
println("f1 a= $a")
}
demo.addFun(f1)
demo.addFun2(f1)
//第二种
demo.addFun(::zz)
demo.addFun2(::zz)
//第三种
demo.addFun {
}
demo.addFun2 {
}
}
【补充】:高阶函数直接传函数作为参数是用双冒号::
【结论】:
1、 在ide上其实看到,第三种情况见区别。1,2情况一样
demo.addFun { this:A
}
demo.addFun2 { it:A
}
这个就是 action: A.() -> Unit 和 action: (A) -> Unit 的区别。一个Lambda参数是this,一个默认参数是it。注意这里action: A.() -> Unit的参数只能是this是不能修改的。action: (A) -> Unit的可以修改。
五、进一步联想和思考
到这里发现action: A.() -> Unit 和 action: (A) -> Unit 就是lambda表示参数 this和it区别的时候
- 一方面还想知道为什么,这个就比较深了今天估计没答案,这个涉及到A.() 的语法。
- 另一方面突然又觉得很熟悉this, it … let,apply 【☺☺☺☺☺】
我记得自己很久以前写过一篇with和apply的:这个
打开源码就很明白了:
//this的
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
//it的
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}