Android 之 Kotlin 的作用域函数
Kotlin作用域函数(apply/also/let/run/with)对比与应用:apply/also返回对象本身,分别用于配置对象(this)和副作用操作(it);let通过it处理可空对象并返回结果;run/with使用this进行对象计算并返回结果。选择依据:对象初始化用apply,日志验证用also,空安全处理用?.let,混合计算用run/with。典型场景包括UI配置、链式调用和数据
Kotlin 的作用域函数(Scope Functions)是一组在对象上下文中执行代码块的高阶函数,通过简洁的语法实现对象操作、空安全处理和链式调用。以下是 5 个核心作用域函数的对比及示例:
一、作用域函数对比表
|
函数 |
引用方式 |
返回值 |
核心用途 |
典型场景 |
|---|---|---|---|---|
|
|
|
对象本身 |
对象配置(设置值) |
初始化对象、设置属性 |
|
|
|
对象本身 |
副作用操作(获取值) |
日志、验证、链式中间处理 |
|
|
|
Lambda 结果 |
空安全处理、数据转换 |
可空对象操作、链式转换 |
|
|
|
Lambda 结果 |
对象计算、混合逻辑 |
访问成员并返回计算结果 |
|
|
|
Lambda 结果 |
非扩展函数版 |
显式传入对象并批量操作 |
二、函数详解与代码示例
1. apply:对象初始化与配置
特点:隐式 this(可省略),返回对象自身。
示例:
// 初始化 TextView 并配置属性
val textView = TextView(context).apply {
text = "Submit" // 等价于 this.text = "Submit"
textSize = 16f
setOnClickListener { showToast() }
}
// 链式配置 AlertDialog
AlertDialog.Builder(this).apply {
setTitle("警告")
setMessage("确认删除?")
}.create()
适用场景:密集配置对象属性(如 UI 组件、DTO 对象)。
2. also:执行副作用操作
特点:显式 it,返回对象自身。
示例:
// 链式调用中插入日志
val file = File("data.txt")
.also { println("创建文件: ${it.path}") } // 打印路径
.also { it.writeText("Hello") } // 写入内容
// 验证并传递对象
val user = User(name = "Alice").also {
require(it.name.isNotEmpty()) // 非空验证
}
适用场景:调试、日志记录、链式调用中的中间操作。
3. let:空安全处理与数据转换
特点:显式 it,返回 Lambda 结果(支持安全调用 ?.let)。
示例:
// 安全处理可空对象
val name: String? = getName()
val greeting = name?.let {
"Hello, ${it.uppercase()}" // it 为非空副本
} ?: "Hello, Guest"
// 链式数据转换
val numbers = listOf(1, 2, 3)
val result = numbers.map { it * 2 }
.let { it.joinToString("-") } // 转换为 "2-4-6"
适用场景:可空对象操作、类型转换、限定临时变量作用域。
4. run:对象计算与混合操作
特点:隐式 this(可省略),返回 Lambda 结果。
示例:
// 计算文件内容长度
val file = File("data.txt")
val length = file.run {
if (exists()) readText().length else 0
}
// 混合对象方法与外部函数
val user = User("Bob", 30)
val info = user.run {
age += 5
"姓名: $name, 年龄: $age" // 返回字符串
}
适用场景:同时访问对象属性和外部函数、链式操作中的计算。
5. with:批量操作已有对象,直接操作这个传入的对象,取值或者使用方法
特点:非扩展函数,显式传入对象,返回 Lambda 结果。
示例:
val list = mutableListOf("A", "B")
val size = with(list) {
add("C") // 直接调用 add()
remove("A") // 无需写 list.remove()
this.size // 返回结果
}
// 数学计算
val point = Point(3, 4)
val distance = with(point) {
sqrt(x * x + y * y) // 直接访问属性
}
适用场景:对已有对象进行多次操作,避免重复写对象名。
三、选择建议(口诀)
-
配置对象 →
apply(this+ 返回自身) -
副作用操作 →
also(it+ 返回自身) -
空安全处理 →
?.let(it+ 返回结果) -
对象计算 →
run/with(this+ 返回结果) -
链式构建 →
apply→also(如obj.apply{}.also{})
最佳实践:
避免混淆返回值:
apply/also返回对象,适合链式配置;let/run/with返回结果(最后一句执行语句),适合生成新值。val nullableStr: String? = getName() var cc = nullableStr?.let { println(it.uppercase()) "Hello, ${it.uppercase()}" //返回最后一句执行语句 } ?: "你好" println(cc) fun getName(): String? { return "zzz"; }
更多推荐



所有评论(0)