美文网首页Kotlin编程Kotlin
Kotin边学边用:apply / with / run / a

Kotin边学边用:apply / with / run / a

作者: 朱和 | 来源:发表于2018-07-24 15:57 被阅读24次

    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边用边学系列

    参考资料

    相关文章

      网友评论

        本文标题:Kotin边学边用:apply / with / run / a

        本文链接:https://www.haomeiwen.com/subject/wnzemftx.html