最近在学习kotlin扩展函数时碰到一个这样的写法:
public inline fun <T> T.apply(block: T.() -> Unit): T {
按正常来说,这个高阶函数的方法应该这样写:
public inline fun <T> T.apply(block: (T) -> Unit): T {
表示接收一个 参数类型为 T 无返回值的方法。
但用T.() 代替 (T) 有什么特殊的地方呢??
先看看为StringBuilder类定义一个正常的扩展函数:
inline fun StringBuilder.add(str : (StringBuilder) -> Unit){
str(this)
}
这个扩展函数接收一个 参数值为 StringBuilder 无返回值的函数。
看一下调用:
原始写法:
StringBuilder().add(fun(sb :StringBuilder){
sb.append(123)
sb.append(456)
sb.append(789)
})
运行结果:
QQ截图20200619124455.png
当然,在kotlin中方法参数是可以用lambda表达式代替的
简化如下:
StringBuilder().add({sb ->
sb.append(123)
sb.append(456)
sb.append(789)
})
当参数只有一个时,可以不用声明
再次简化:
QQ截图20200619124831.png
运行结果:
QQ截图20200619124455.png
可以看到运行结果都是一致的,而最后,我们传入的参数,可以用kotlin默认提供的it来代替。
再次回到开始的问题,那T.()会变成什么样子呢?
改一下看看:
inline fun StringBuilder.add(str : StringBuilder.() -> Unit){
str(this)
println(this.toString())
}
调用:
QQ截图20200619124931.png
可以看到 原来的it不见了, 转而用this代替了,于是我们就可以这么写:
QQ截图20200619125030.png
从这里可以看出 (T) 和 T.() 这两种写法不同之处在于 :
使用(T) 调用时默认使用it指代参数。
使用 T.() 调用时默认使用this指代参数。
后者代码更少了。
于是联想到kotlin中的标准函数let(), applay()
它们一个是it 一个是this 看看它们内部实现是怎样的:
let():
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
applay()
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
可以看到它们中一个用的是(T) 一个用的是T.() 正好和前面吻合。
而且使用T.()这种方式, 在调用函数时,有两种方式:
inline fun StringBuilder.add(str : StringBuilder.() -> Unit){
//1.
// str(this)
//2.
this.str()
println(this.toString())
}
这两种调用方式输出的结果是一致的,第二种方式相对来说还是有点难以接受的~~~
完。
网友评论