let
函数签名
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
复制代码
使用场景
- 针对一个可
null
对象统一做判空处理,避免写一些判断null
的操作
// 如果 object 为 null,则 let 闭包中的方法不会被执行
// 如果 object 不为 null,则 let 闭包中默认的 it 变量为不可选类型
object?.let {
it.doSomething()
// 闭包的返回值
"xxx"
}
复制代码
- 使用
it
替代object
对象去访问公有的属性 & 方法
// 无论 object 是否为空均会执行,则 let 闭包中默认的 it 变量和 object 保持一致
object.let {
it.doSomething()
// 闭包的返回值
"xxx"
}
复制代码
使用示例
闭包不为空时执行闭包
block?.let { block(it) }
复制代码
also
函数签名
public inline fun <T> T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
// 闭包的返回值为 this
return this
}
复制代码
和 let 区别
let
: 返回值为最后一行also
: 返回值为this
所以在函数没有返回值的情况下,let
和 also
并无差别。
使用场景
在变量初始化的时候给变量的属性赋值
val object = Object().also {
it.xxx = "xxx"
it.doSomething()
}
复制代码
with 函数
函数签名
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
复制代码
使用场景
调用一个对象的多个方法或者设置多个属性时,可以省去对象名,直接调用
// 闭包里面的变量为 this,而不是 it
with(object) {
// 这里就相当于 object.doSomething()
doSomething()
// 闭包的返回值
xxx
}
复制代码
run
函数签名
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
复制代码
作用
结合了 let
和 with
两个函数的作用
- 可以判空
- 直接调用,无需
it
使用场景
object?.run {
doSomething()
}
复制代码
apply
函数签名
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
复制代码
和 run 区别
run
的返回值为闭包的最后一行apply
的返回值为this
使用场景
可以更方便的写链式调用
class Test {
fun test() = apply {
doSomething()
}
fun test1() = apply {
doSomething()
}
}
// other class
Test().run {
test().test1()
}
复制代码
总结
由于 let/also/run/apply
均为 T
的扩展函数,所以均支持链式调用。他们的区别只在于参数和返回值是否相同。
如果抉择
let/run
由于返回值为最后一行,更适用于一次执行。
also/apply
由于返回值为 this
,更适用于链式调用。
选择使用 this
还是 it
访问当前对象,一个原则就是:如果使用 this
,那么就不要把 this.
写出来,利用 this
关键字可以省略的特性。
特殊点
(T) -> R
可以看成是把 this
当成参数传入闭包中进行处理。
而 T.() -> R
可以看成是给 T
类型的类扩展了一个 () -> R
的属性,当 receiver.block()
被执行的时候,相当于 T
类型中扩展的 () -> R
类型的闭包被执行了。
详情可以去看一下 kotlin
中闭包以及扩展属性/函数。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END