Key Takeaways(划重点):
- let it run with dream
- it also applies to self
- 有显式使用 this 时,请换成 it 调用
- 可为
null
时别和with搭档
背景
Kotlin是一门简洁、高效的语言,为此,它的if
、when
、throw
都支持expression而非Java的纯Statement,其官方的Coding Conventions也有如下建议:
Prefer using an expression body for functions with the body consisting of a single expression.
与此同时,Kotlin更是提供了5个类似的、便于在对给定对象的上下文下执行区块代码的函数(to execute a block of code in the context of a given object):T.apply, with, run/T.run, T.also, T.let。官方也提供了这5个函数的使用建议:Using scope functions apply/with/run/also/let。这个官方建议相对而言比较高屋建瓴或者说比较抽象,具体使用的时候还是得猜/试/蒙,这和我们严谨的程序员作风严重不符。
纯接口分析
先撇开run的其中一个光杆变体(其实也没分析它的必要),直接对5个函数定义进行分析:
T.also((T) -> Unit): T
T.apply(T.() -> Unit): T
T.let((T) -> R): R
T.run(T.() -> R): R
with(T, T.() -> R): R
直观的结论就是:
-
also, apply的返回值是自身,差异是
- also是参数(it)
- apply是扩展函数(this)
-
let, run, with的返回值是被执行函数体的返回值,差异是
- let是参数(it)
- run和with是扩展函数(this)
上述的差异可以通过简单的两句顺口溜陈述:
- let it run with dream
- it also applies to self
简单的分词来帮助记忆(参考下表):
- let是it(参数),run和with是this(扩展函数),返回值是dream(被执行函数体的返回值)
- also是it(参数),apply是this(扩展函数),返回值是self(自身)
it分区 | this分区 | 返回值 |
---|---|---|
let it | run with | dream |
it also | applies (apply) | to self |
所以技术层面得到的这两句顺口溜应该能清晰的让我们知道这5个函数的差异了,剩下的就是如何把这些函数用在适合的场景了。
适用场景差异分析
首先清晰的返回值差异已经可以决定是走第一句还是第二句顺口溜,剩下的就是确定是走参数 it 还是 扩展函数 this。
这个其实通过代码就能很清晰的看出结论来:(取自Kotlin官方样例)
// Nice.
val foo = createBar().also {
currentBar = it // Accessing property of Baz
observable.registerCallback(it) // Passing context object as argument
}
// Yack!
val foo2 = createBar().apply {
currentBar = this // Accessing property of Baz
observable.registerCallback(this) // Passing context object as argument
}
// Nice.
val foo: Bar = createBar().apply {
color = RED // Accessing only properties of Bar
text = "Foo"
}
// Yack!
val foo2: Bar = createBar().also {
it.color = RED // Accessing only properties of Bar
it.text = "Foo"
}
很明显,参数形式的it.color = RED
肯定不如扩展函数的color = RED
简洁。
this的话,由于Kotlin支持多种scope,因此this的出现会让人比较难以理解到底指向的是哪个。一般而言,扩展函数中如果出现了显式的this调用,那就不如改成参数(it)的方式更容易理解的。
通过代码的分析,我们可以得出:有显式使用this时,请换成it调用。
nullable的分析
直接看代码吧:
// Nice.
person?.run {
awarded = true
award = "Big Stuff"
}
// Yack!
with(person) {
this?.awarded = true
this?.award = "Big Stuff"
}
对于with,nullable
的处理就远不如其他几个来的方便了。
所以:可为null
时别和with搭档
汇总下来就是:
- let it run with dream
- it also applies to self
- 有显式使用this时,请换成it调用
- 可为
null
时别和with搭档
希望这四条顺口溜能对你有所帮助,喜欢的话点个赞吧!
更多Kotlin的实用技巧,请参考《Kotlin边用边学系列》