Kotlin边用边学:4句顺口溜驯服apply / with / run / also / let

Key Takeaways(划重点)

  • let it run with dream
  • it also applies to self
  • 有显式使用 this 时,请换成 it 调用
  • 可为null时别和with搭档

背景

Kotlin是一门简洁、高效的语言,为此,它的ifwhenthrow都支持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

简单的分词来帮助记忆(参考下表):

  • letit(参数)runwiththis(扩展函数),返回值是dream(被执行函数体的返回值)
  • alsoit(参数)applythis(扩展函数),返回值是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"
    }

对于withnullable的处理就远不如其他几个来的方便了。

所以:可为null时别和with搭档

汇总下来就是:

  • let it run with dream
  • it also applies to self
  • 有显式使用this时,请换成it调用
  • 可为null时别和with搭档

希望这四条顺口溜能对你有所帮助,喜欢的话点个赞吧!

更多Kotlin的实用技巧,请参考《Kotlin边用边学系列》

参考资料

  • Mastering Kotlin standard functions: run, with, let, also and apply
  • The difference between Kotlin’s functions: ‘let’, ‘apply’, ‘with’, ‘run’ and ‘also’
  • Intention of Kotlin's "also apply let run with"

你可能感兴趣的:(Kotlin边用边学:4句顺口溜驯服apply / with / run / also / let)