Kotlin - let、run、with、apply、also 函数

引用

https://medium.com/mobile-app-development-publication/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84


前言

今天在 medium 上看到了一篇很好的文章,比自己的总结好多了,下图来自 medium 的文章。

主要从三个角度来区分函数的使用:

  1. 函数的返回值:返回函数的接收者或者 lambda 表达式的最后一行。
  2. 函数的参数: it 还是 this。
  3. 是否需要空检查和链式调用。
Kotlin - let、run、with、apply、also 函数_第1张图片

Kotlin - let、run、with、apply、also 函数

let、run、with、apply、also 这些函数比较抽象,看别人教程一脸懵逼。

一定不要记忆概念性的东西,不要去强制记忆函数的用法。

只需要记住,apply 、also 函数返回的是对象本身,其余函数的返回结果为 lambda 表达式的最后一行结果。至于其函数参数的含义,打开 IDEA,勾选显示方法的参数名称,如下图:

Kotlin - let、run、with、apply、also 函数_第2张图片

忘记函数怎么用时,看下 IDEA 的提示即可,如下图:

Kotlin - let、run、with、apply、also 函数_第3张图片

如果你连函数调用返回结果都忘记了的话,可以点击 IDEA 的对应函数,查看函数的声明:

Kotlin - let、run、with、apply、also 函数_第4张图片

内联扩展函数 - let

let 函数经常用于如果一个对象不为空,则执行某段代码,Java 中经常这样写:

if(object !=null){
// todo
}

Kotlin 中可以这么写:

object?.let{
}

let 函数的最后一行为 lambda 表达式的结果。

如下图,在 person 的后边按下 alt+ enter 键。IDE 会提示,let 函数可以转换为 if 语句。
Kotlin - let、run、with、apply、also 函数_第5张图片


内联函数 - with

with 函数后边跟对象,其花括号内部可以使用 this 来表示对象(感觉花括号就是创建了该对象的上下文环境)。

    var kotlinDemo: KotlinDemo? = KotlinDemo()
    with(kotlinDemo) {
        print(hello()) // 编译报错, 因为 kotlinDemo 可能为null
        print(this.hello()) // 编译报错, 因为 kotlinDemo 可能为null
        print(this?.hello()) // 编译通过
    }

with 使用场景:当确定一个对象非空的时候,并且调用了该对象的很多方法,可以使用 with 来简化代码:

    var kotlinDemo = KotlinDemo()
    // 写起来比较繁琐
    kotlinDemo.hello()
    kotlinDemo.hello1()
    kotlinDemo.hello2()
    kotlinDemo.hello3()

    // 使用 with 简化代码:
    with(kotlinDemo) {
        hello()
        hello1()
        hello2()
        hello3()
    }

with 后边也可以跟一个可能为 null 的对象,但是需要在花括号内部进行判断,代码比较丑陋。此时可以使用 run 函数来替代 with 函数


内联扩展函数 - run

run 函数是 with 函数和 let 函数的结合体,其使用方法和 let 类似,并且其花括号内部可以使用 this 来表示对象:

    var kotlinDemo: KotlinDemo? = KotlinDemo()
    kotlinDemo?.run {
        hello()
        hello1()
        hello2()
        hello3()
    }

上述代码也可以使用 let 函数来写,但是 let 函数 lambda 表达式的参数为 it(it 为单个参数的隐式名称 ):

    kotlinDemo?.let {
        it.hello()
        it.hello1()
        it.hello2()
        it.hello3()
    }

不要记忆函数的替换。在 IDEA 中,光标移动到 run,按下 alt+enter 键,IDEA 会提示可以将 run 函数转换为 let 函数:

Kotlin - let、run、with、apply、also 函数_第6张图片

内联扩展函数 - apply

apply 函数与 run 函数类似,不同点是 apply 函数的闭包返回值为对象本身,而 run 函数返回值是 lambda 表达式最后一行的值,例如上面的例子可以直接用 apply 替换:

    kotlinDemo?.apply {
        hello()
        hello1()
        hello2()
        hello3()
    }

apply 使用场景:一般用在多级判空的情况下,如一个复杂对象 A.B.C ,即对象 A 有个成员变量为对象 B,对象 B 有个成员变量为对象 C,三者都有可能为空。使用 Java 代码时候,可能比较丑陋:

        if (A != null) {
            //  do something
            if (A.B != null) {
                //  do something
                if (A.B.C != null) {
                    //  do something
                }
            }
        }

使用 apply 函数多级判空:

    A?.apply {
         // A 不为空的情况下,执行 apply 里面的逻辑后,返回 A
    }?.B?.apply {
        // 如果 A 中的 B 成员变量不为空,执行 apply 里面的逻辑后,返回 B
    }?.C?.apply {
         // 如果 B 中的 C 成员变量不为空,执行 apply 里面的逻辑后,返回 C
    }

内联扩展函数 - also

also 函数的使用和 let 函数类似。两者的区别是返回值不同, let 函数返回的是 lambda 表达式最后一行的值。 also 函数返回的是传入对象本身。例如上述代码使用 also 函数来写:

    kotlinDemo?.also {
        it.hello()
        it.hello1()
        it.hello2()
        it.hello3()
    }

小结

初学这些函数一定比较懵,大多数情况下,上述的几个函数都能够相互替换,就是给改改写法。从 lambda 表达式的参数和 lambda 表达式返回值区分:

函数 说明
let lamnda 表达式参数为 it ,it 为单个参数的隐式名称,即对象本身。 返回值为 lambda 表达式最后一行的值。
with with 后面跟对象,lambda 表示中使用 this 表示对象本身,返回值为 lambda 表达式最后一行的值。with 后面对象可能为空时,需要在 lambda 表达式内部做空安全判断。
run let + with。 lambda 表示中使用 this 表示对象本身,返回值为 lambda 表达式最后一行的值。
apply 和 run 类似, lambda 表示中使用 this 表示对象本身,返回值为对象本身。
also 和 let 类似, lamnda 表达式参数为 it ,it 为单个参数的隐式名称,即对象本身。返回值为对象本身。

将 let 、with、run 这三个分为一组对比。
将 let、also 分为一组对比,将 run、apply 分为一组对比。

apply、also 还有一个作用就是能实现链式调用,代码更加简洁。

虽然表面上这些函数都很像,其实还是有不同的使用场景。

还是那句话,不要记忆上述概念,忘记怎么使用了,打开 IDEA,看 IDEA 给你的提示。

你可能感兴趣的:(Kotin)