如何选择Kotlin作用域函数-let,run,with,apply

⏰ : 全文字数:2326+

🥅 : 内容关键字:作用域函数,kotlin,let,run,apply

🤙 : 公_众_号:七郎的小院

🥅 : 更多文章:blog.softgeek.cn

如何选择这些作用域函数

在Kotlin开发中,经常使用到let,apply,also,run等一些作用域函数,具体什么是作用域函数,可以看下官网地址作用域函数,这里不在展开讲,不明白的可以看下官方文档。

我们在实际使用中,你会是否会有这样的疑惑,到底 使用那个作用域函数,好像有些情况,每个都可以。有 些情况,又只能用特定的函数?

其实要弄明白这些,就需要弄明白这些函数的特点。而要区分这些函数的差异,我们可以从三个维度来进行区分,分别是:是否是扩展函数、返回值差异、参数是什么。可以看下下面的表格:

函数 对应引用方式 返回值 是否是扩展函数
let it Lambda result Yes
run this Lambda result Yes
run - Lambda result No: called without the context object
with this Lambda result No: takes the context object as an argument.
apply this Context object Yes
also it Context object Yes

上面的表格是官网中的表格,列举了各个函数在各个维度的差异。但是看起来还是觉得不够直观,所以这里我做一个选择使用那个函数的 "抉择图",可以看下

所以下次不知道用哪个,就可以照着这个图选就行了~~~

使用问题

现在kotlin基本上是开发的主力语言,开发中也是大量使用到作用域函数。但是使用作用域函数的时候,碰到了一些比较典型问题。这些问题在review其他人代码时也会看到,说明大家可能都碰到了这些问题,这里选取最常见的两个进行说明。

1、过多嵌套使用

经常看到代码中有很多嵌套使用作用域函数的场景,举个例子:

kotlin 复制代码
    fun getUserFriendsInfo() {
        userId?.let {
            val userInfo = getUserInfo(it)
            userInfo?.apply {
                val friends = getFriendsByUserInfo(userInfo)
                friends?.apply {
                    ......
                }
            }
        }
    }

从上面的代码可以看到,如果过多使用嵌套作用域函数,就会形成类似"回调地狱"的代码形式,再加上代码中还用到了一些lambdas,情形更加严重,导致代码极其难看。在我们的项目中,经常看到类似的代码。那么有什么办法改善呢?

我认为有如下几个方法:

  • 一个是把代码进行抽离,放到不同的函数中,减少嵌套
  • 很多情况都是为了判空,我们可以提前做空判断,或者定义Contract,后续的该变量都是用非空状态,这样就不用到处判断,减少嵌套

2、参数this/it、引用混淆

有些作用域函数是有参数传递的,有些是this,有些是it,而如果嵌套使用,就会出现代码可读性的问题,甚至引起错误,举几个例子:

第一个例子:

kotlin 复制代码
    fun getUserFriendsInfo() {
        userId?.let {
            val userInfo = getUserInfo(it)
            userInfo?.let {
                val friends = getFriendsByUserInfo(it)
                friends?.let {
                    println(it)
                    ......
                }
            }
        }
    }

上面代码,可以看到有三个it,到底是那个是哪个,有时候并不一定好区分。同样其他参数是it的作用域函数也有这个问题。

第二个例子:

kotlin 复制代码
class Style() {
    var width = 0.0
    var height = 0.0
    var name = ""
}

class Widget(val name: String, val width: Double) {
    val style: Style
    
    init {
        val height = width * 1.5
        style = Style().apply {
            width = width
            name = name
        }
    }
}

上面代码中,apply方法里面。Widgetwidth、nameStyle的同名,有时候就无法分辨清楚,甚至报错。 这些情况该怎么处理呢?

  • 不要使用默认的命名,比如it,尽量重命名有意义的名字
  • 不要大量嵌套使用作用域函数
  • apply这种没有办法重命名参数的作用域函数,在引用变量的时候,可以借助label标签,比如上面apply的例子
kotlin 复制代码
class Widget(val name: String, val width: Double) {
    val style: Style

    init {
        val height = width * 1.5

        style = Style().apply {
            // 使用标签
            this.width = this@Widget.width 
            this.height = height
            this.name = this@Widget.name
        }
    }
}
相关推荐
匆忙拥挤repeat16 分钟前
Android Compose 渲染 UI 帧的三个阶段:组合、布局、绘制
android·ui
帅得不敢出门28 分钟前
Android Studio同一个工程根据不同芯片平台加载不同的framework.jar及使用不同的代码
android·android studio·jar
xiangxiongfly91542 分钟前
Android LeakCanary源码分析
android·leakcanary
黄林晴42 分钟前
紧急预警!Android 17 定位权限大改,你的 App 要适配了
android
夏沫琅琊1 小时前
Android API 发送短信技术文档
android·kotlin
周周不一样1 小时前
Android基础笔记1
android·笔记·gitee
取码网2 小时前
影视APP源码 SK影视 安卓+苹果双端APP 反编译详细视频教程+源码
android
musk12122 小时前
android webview 黑屏问题 , 页面加载时间有点长的情况下
android
夏沫琅琊2 小时前
Android 彩信导出技术文档
android·kotlin