https://medium.com/mobile-app-development-publication/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84
今天在 medium 上看到了一篇很好的文章,比自己的总结好多了,下图来自 medium 的文章。
主要从三个角度来区分函数的使用:
let、run、with、apply、also 这些函数比较抽象,看别人教程一脸懵逼。
一定不要记忆概念性的东西,不要去强制记忆函数的用法。
只需要记住,apply 、also 函数返回的是对象本身,其余函数的返回结果为 lambda 表达式的最后一行结果。至于其函数参数的含义,打开 IDEA,勾选显示方法的参数名称,如下图:
忘记函数怎么用时,看下 IDEA 的提示即可,如下图:
如果你连函数调用返回结果都忘记了的话,可以点击 IDEA 的对应函数,查看函数的声明:
let 函数经常用于如果一个对象不为空,则执行某段代码,Java 中经常这样写:
if(object !=null){
// todo
}
Kotlin 中可以这么写:
object?.let{
}
let 函数的最后一行为 lambda 表达式的结果。
如下图,在 person 的后边按下 alt+ enter 键。IDE 会提示,let 函数可以转换为 if 语句。
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 函数是 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 函数:
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 函数的使用和 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 给你的提示。