oynix

于无声处听惊雷,于无色处见繁花

Kotlin之let、apply、also、with

自从前两年的I/O大会上,Google官方宣布Kotlin-first后,越来越多的Android由Java转向了Kotlin。而使用Kotlin常常要碰上标题中的这几个函数,它们之间有着相似的地方,但也有各自的不同。放在一起,横向对比,便于记忆,在此做个记录。

分类

这几个函数均来自kotlin-stdlib库中的Standard.kt文件,同样在这个文件中还有另外几个函数,一块说一说。

按照类型可以分为两类,一类是顶层函数,一类是扩展函数。

这几个函数的参数中,基本都有一个代码块参数block,T.() -> R表示block的参数是T.this,(T) -> R表示block的参数是T,也就是it。

顶层函数有:

1
2
3
4
5
6
7
8
9
public inline fun TODO(): Nothing 

public inline fun TODO(reason: String): Nothing

public inline fun repeat(times: Int, action: (Int) -> Unit)

public inline fun <R> run(block: () -> R): R

public inline fun <T, R> with(receiver: T, block: T.() -> R): R

其中,TODO是用来标记尚未实现的空方法,repeat用来重复执行传入的action,这两个就不多说了,我们来对比一下withrun

名称 block参数 返回值
run block()
with T.this block()

扩展函数有:

1
2
3
4
5
6
7
8
9
10
11
public inline fun <T, R> T.run(block: T.() -> R): R 

public inline fun <T> T.apply(block: T.() -> Unit): T

public inline fun <T, R> T.let(block: (T) -> R): R

public inline fun <T> T.also(block: (T) -> Unit): T

public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T?

public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T?

其中,takeIf表示传入的predicate为true时,返回T,false返回null,而takeUnless恰恰相反,false时返回T,true时返回null。

然后,我们来一块看一下剩下的4个函数。其实根据block的传入参数,和返回值的对比,区别就很清晰了。
传入参数有两种:T.this 和 T
返回值有两种:T 和 block()
两种传入参数和两种返回值,两两组合,就有了这4个函数

名称 block参数 返回值
run T.this block()
apply T.this T
let T block()
also T T

通过表格对比,就更加清晰了

应用

从传入参数来看,传T.this和T是类似的,传入T.this时,调用T的方法通过this.调用;传入T时,调用T的方法通过it.调用。
如果你不关心扩展函数的返回值,那么随便你用哪个,本质上的区别并不大。
如果关心扩展函数的返回值,当需要修改T中的一些成员的时候,考虑使用applyalso;当需要通过T来得到一个结果的时候,考虑使用runlet

总结

这些个函数,都是Kotlin为了方便开发者写代码而设计的,如果你一个都不用,这完全没有问题。如果要用的话,就要清楚它们之间的区别和联系。

------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2021/08/a911d3b22245/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道