当前位置: 代码迷 >> 综合 >> 【Kotlin】标准函数
  详细解决方案

【Kotlin】标准函数

热度:62   发布时间:2024-02-10 20:22:00.0

本文讲解 Kotlin 标准函数 let、with、run、apply、also 的用法。

? 官方文档

 

Kotlin 的标准函数指的是 Standard.kt 文件中定义的函数,任何 Kotlin 代码都可以自由地调用所有的标准函数。


一、let

? let 官方文档

// 示例代码
obj.let { obj2 ->// TODO: 编写具体的业务逻辑
}

作用:调用了 obj 对象的 let 函数,然后 Lambda 表达式中的代码就会立即执行,并且这个 obj 对象本身还会作为参数传递到 Lambda 表达式中。为了防止变量重名,这里将参数名改成了 obj2,但实际上它们是同一个对象。

 

示例:

创建一个 Study 接口,在接口中定义两个待实现函数:

interface Study {fun readBooks()fun doHomework()
}

创建一个  doStudy() 函数,接收 Study 类型的参数:

fun doStudy(study: Study?) {if (study != null) {study.readBooks()}if (study != null) {study.doHomework()}
}

进行一次 if 判断就能随意调用 study 对象的任何函数,但受制于 ?. 操作符的限制,每次调用 study 对象的函数时都要进行一次 if 判断。

 

结合使用 ?. 操作符和 let 函数对代码进行优化:

fun doStudy(study: Study?) {study?.let {it.readBooks()it.doHomework()}
}

?. 操作符表示对象为空时什么都不做,对象不为空时就调用 let 函数,而 let 函数会将 study 对象本身作为参数传递到 Lambda 表达式中,此时的 study 对象肯定不为空,我们就能放心地调用它的任意方法了。

 


二、with

? with 官方文档

// 示例代码
val result = with(obj) {// TODO: 这里是 obj 的上下文// with 函数的返回值"value"
}

作用:它可以在连续调用同一个对象的多个方法时让代码变得更加精简。

 

示例:

有一个汽车品牌列表,现在想打印出列表中所有汽车品牌的名字,未使用 with 函数的写法:

fun main() {val list = listOf("BMW", "BENZ", "AUDI", "TOYOTA", "HONDA")val builder = StringBuilder()builder.append("Car brand: \n")for (car in list) {builder.append(car).append("\n")}builder.append("Done.")val result = builder.toString()println(result)
}

运行代码,Log 如下:

Car brand: 
BMW
BENZ
AUDI
TOYOTA
HONDA
Done.

示例代码使用 StringBuilder 构建字符串,最后将结果打印出来。但是连续调用了很多次 builder 对象的方法。

 

使用 with 函数来精简代码:

fun main() {val list = listOf("BMW", "BENZ", "AUDI", "TOYOTA", "HONDA")val result = with(StringBuilder()) {append("Car brand: \n")for (car in list) {append(car).append("\n")}append("Done.")toString()}println(result)
}

说明:给 with 函数的第一个参数传入了一个 StringBuilder 对象,那么接下来整个 Lambda 表达式的上下文就会是这个 StringBuilder 对象。于是我们在 Lambda 表达式中就不用再像刚才那样调用 builder.append() 和 builder.toString() 函数了,而是可以直接调用 append() 和 toString() 函数。Lambda 表达式的最后一行代码会作为 with 函数的返回值返回。


 

三、run

? run 官方文档

// 示例代码
val result = obj.run {// TODO: 这里是 obj 的上下文// run 函数的返回值"value"
}

run 函数的用法和使用场景和 with 函数非常类似,只是稍微做了一些语法改动而已。首先 run 函数不能直接调用的,而是一定要调用某个对象的 run 函数才行;其次 run 函数只接收一个 Lambda 参数,并且会在 Lambda 表达式中提供调用对象的上下文。其他方面和 with 函数是一样的,包括也会使用 Lambda 表达式中的最后一行代码作为返回值返回。

 

使用 run 函数来修改汽车品牌这段代码:

fun main() {val list = listOf("BMW", "BENZ", "AUDI", "TOYOTA", "HONDA")val result = StringBuilder().run {append("Car brand: \n")for (car in list) {append(car).append("\n")}append("Done.")toString()}println(result)
}

说明:只是将调用 with 函数并传入 StringBuilder 对象改成了调用 StringBuilder 对象的 run 方法。

 


四、apply

? apply 官方文档

// 示例代码
val result = obj.apply {// TODO: 这里是 obj 的上下文
}

apply 函数和 run 函数也是极其类似的,都要在某个对象上调用,并且只接收一个 Lambda 参数,也会在 Lambda 表达式中提供调用对象的上下文,但是 apply 函数无法指定返回值,而是会自动返回调用对象本身,

 

使用 apply 函数修改汽车品牌这段代码:

fun main() {val list = listOf("BMW", "BENZ", "AUDI", "TOYOTA", "HONDA")val result = StringBuilder().apply {append("Car brand: \n")for (car in list) {append(car).append("\n")}append("Done.")}println(result.toString())
}

说明:由于 apply 函数无法指定返回值,只能返回调用对象本身,因此这里的 result 实际上是一个 StringBuilder 对象,最后打印的时候再调用它的 toString() 函数才行。

 


五、also

? also 官方文档

// 示例代码
obj.also {// TODO: 这里是 obj 的上下文
}

also 函数的结构实际上和 let 很像,唯一的区别就是返回值的不一样,let 是以闭包的形式返回,返回函数体内最后一行的值,如果最后一行为空就返回一个 Unit 类型的默认值;而 also 函数返回的则是传入对象的本身。

 

使用 also 函数修改学习这段代码:

fun doStudy(study: Study?) {study?.also {it.readBooks()it.doHomework()}
}

also 函数使用前后和 let 函数类似。

 


适用场景:

let 适用于处理不为 null 的操作场景
with 适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可,经常用于 Android 的 RecyclerView 的 onBinderViewHolder 中,数据 model 的属性映射到 UI 上
run 适用于 let、with 函数任何场景
apply 1. 适用于run函数的任何场景,一般用于初始化一个对象实例的时候,操作对象属性,并最终返回这个对象
2. 动态inflate出一个XML的View的时候需要给View绑定数据也会用到
3. 一般可用于多个扩展函数链式调用 
4. 数据model多层级包裹判空处理的问题
also 适用于 let 函数的任何场景,一般可用于多个扩展函数链式调用

 

如果本文对你有帮助,请点赞支持!!!