前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >13. Kotlin 作用域函数 run/let/apply/also 的使用

13. Kotlin 作用域函数 run/let/apply/also 的使用

作者头像
sickworm
发布2020-05-06 21:08:23
1.5K0
发布2020-05-06 21:08:23
举报
文章被收录于专栏:sickworm

上一篇文章我们介绍了作用域函数,并以其中一个作用函数run为例,介绍了作用域函数的使用和原理。除了run之外,Kotlin 官方还内置了letapplyalso这几个作用域函数,下面我们一起来他们的相同点和区别,并举例说明他们的使用场景。

1. 4 个作用域函数 = 2 个特性的两两组合

runletapplyalso,这 4 个作用域函数,其实是 2 个特性的组合结果:

  • 调用作用域函数的对象,是作为this传入,还是作为唯一参数(默认为it)传入;
  • 作用域函数的返回值,是调用的对象,还是 lambda 的返回值。

配合伪代码解释一下:

代码语言:javascript
复制
val result = object.xxx { param ->
    val lambdaResult = param.toString()
    lambdaResult
}

xxx可以是runletapplyalso其中一个。

如果xxx = run/let,那么 result == lambdaResult; 而如果xxx = apply/also,那么result == object。且lambdaResult这一行会报错,因为applyalso“` 的 lambda 返回值必须是 Unit。

lambda 最后一行的值会作为 lambda 的返回值。它等价于 return@xxx lambdaResult@xxx表示返回的是这个lambda,而不是退出整个上层方法。如果是不在最后一行返回的代码,比如异常分支,就可以(也只能)这样用。

如果xxx = let/also,那么param == object; 而如果xxx = run/apply的话,那么 lambda 是个无参数 lambda,不存在paramparam -> 这里会报错;

如果 lambda 为单参数 lambda,此时param ->可以省略,Kotlin 提供默认的单参数名it。这个很方便,文章后面的代码都会采用这种简写。

总结成表就是:

特性

返回值为this

返回值为lambda结果

调用对象转换为this

apply

run

调用对象转换为it

also

let

我们只需要知道 4 个作用域函数分别是 2 个特性的两两组合即可。用的时候直接查源代码,不需要专门记忆。

2. run/let/apply/also 各自的使用场景举例

我们已经知道这 4 个作用域函数的特点了,那么我们怎么用好它们呢?下面一起来看下这几个作用域函数的使用场景。

run

这是工程中的一段代码:

代码语言:javascript
复制
mRecordViewHelper?.run {
    mEffectsView.visibility = View.INVISIBLE
    mLyricViewer.visibility = View.INVISIBLE
    mStatusView = AudioRecordStatusView(CommonContext.getApplicationContext(), null)
    enableSoloCountBackView()
}

run方法很适合用在对某个对象做一系列操作的地方。这里可空对象mRecordViewHelper使用run方法把自己转换成非空对象this“传入”到 lambda 中,并在 lambda 内部进行一系列的赋值和方法调用。

run的返回值是 lambda 的最后一行结果,在这个例子是Unit。使用 lambda 结果的用例较少,主要就是这种转换为this的用法。如果后续遇到特别适合的再补充。

let

使用run还是使用let更像是一个个人喜好的问题,因为有些人就是不习惯把调用对象转换成this,而是更喜欢用入参it

使用run还是使用let的确没有太大区别。不过还是有这几种情况,我更建议你用let

  • 调用对象主要作为参数,而不是用于初始化或方法调用时。
代码语言:javascript
复制
// 赋值和调用的方法都是类的成员和方法,不是 mRecordViewHelper 的成员和方法
mRecordViewHelper?.run {
    myFirstView = firstView
    mySecondView = secondView
    setTargetView(targetView)
}

// 使用 let,不会存在两个 this 混用,代码可读性更高。
mRecordViewHelper?.let {
    myFirstView = it.firstView
    mySecondView = it.secondView
    setTargetView(it.targetView)
}
  • 当 lambda 中需要用到类的this时;
代码语言:javascript
复制
// 因为 this 的变化,导致引用类的 this 需要加@MainActivity。这个和 Java 匿名类的 MainActivity.this 效果一样
mRecordViewHelper?.run {
    setOnClickListener(this@MainActivity)
}

// let 不会改变 this,在需要引用类的 this 的时候比较方便。
mRecordViewHelper?.let {
    it.setOnClickListener(this)
}

总结一下:当 lambda 主要执行的是调用对象的方法和赋值时,建议使用run;而当调用对象主要用作参数时,建议使用let。当 lambda 会用到类的this时,建议使用let

apply

applyrun的区别主要在于,apply返回的是调用对象。这个特性使得apply很适合用来做类似初始化的工作。如:

代码语言:javascript
复制
class VideoConfig {
    val profile = VideoEncodeProfile().apply {
        audioBitRate = 44100
        videoWidth = 480
        videoHeight = 480
        videoFrameRate = 30
        setDefaultQuality()
    }
}

apply 也很适合用来做 property 的初始化,这样 property 的初始化代码就不用写在 init 块里了,做到了代码的高内聚。上面代码的profile 就是 property 初始化的例子。

also

also 的适用场景,和runlet一样,是与apply来对比的。具体建议也和runlet一样:

当 lambda 主要执行的是调用对象的方法和赋值时,建议使用apply;而当调用对象主要用作参数时,建议使用also。当 lambda 会用到类的this时,建议使用also

3. 只有 4 个作用域函数吗?

细心的同学可能已经发现,在 Standard.kt 中,除了runletapplyalso之外,还有好几个作用域函数。其实掌握了这 4 个作用域函数,已经覆盖了大部分使用场景。剩下的几个使用需求没有那么的迫切,但掌握之后,可以帮助你写出更有 Kotlin 味道的代码。

下一篇文章会介绍 Standard.kt 中剩余的作用域函数。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 4 个作用域函数 = 2 个特性的两两组合
  • 2. run/let/apply/also 各自的使用场景举例
    • run
      • let
        • apply
          • also
          • 3. 只有 4 个作用域函数吗?
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档