作用域函数(Scope Functions)是Kotlin标准库中的特殊函数,允许在对象上下文中执行代码块。核心作用包括:
- 简化对象操作
- 增强代码可读性
- 减少临时变量
- 链式调用支持
五大作用域函数对比
| 函数 | 上下文引用 | 返回值 | 扩展函数 | 典型应用场景 |
|---|---|---|---|---|
let | it | lambda结果 | 是 | 非空对象处理/数据转换 |
run | this | lambda结果 | 是 | 对象初始化/计算返回值 |
with | this | lambda结果 | 否 | 对象多操作/无返回值操作 |
apply | this | 对象本身 | 是 | 对象配置/属性批量设置 |
also | it | 对象本身 | 是 | 附加操作/日志记录 |
三、详细用法解析
1. let函数
- 用途:常用于对对象进行非空检查(null-check)和链式调用。
- 语法特点:将对象作为
it参数传入 lambda 表达式,并返回 lambda 表达式的最后一行结果。 - 示例:
val name: String? = "Kotlin"
val length = name?.let {
println("当前字符串是:$it")
it.length // 返回字符串的长度
}
println("字符串长度:$length")// 不推荐
user?.let { user ->
address?.let { addr ->
// 多层嵌套影响可读性
}
}
// 推荐改用安全调用链
user?.address?.city?.let { city ->
showLocation(city)
}2. run
- 用途:既可以用来执行代码块,也可以用来计算返回值。常用于需要对象上下文(this)的场景。
- 语法特点:在 lambda 表达式中,使用
this指代调用者,返回 lambda 表达式的最后一行结果。 - 示例:
data class Person(var name: String, var age: Int)
val person = Person("Alice", 25)
val description = person.run {
// 在此 lambda 中,可以直接使用属性 name 和 age
"姓名:$name, 年龄:$age"
}
println(description)扩展函数版
val result = service.run {
port = 8080
start() // this可省略
queryStatus().code // 返回最终结果
}3. with
- 用途:常用于对某个对象进行多次操作,并且不需要返回对象本身。
- 语法特点:不是扩展函数,而是一个普通函数,接受一个对象和 lambda 表达式,lambda 中的
this指代该对象。 - 示例:
val numbers = mutableListOf(1, 2, 3)
val result = with(numbers) {
add(4)
add(5)
// 返回列表的大小
size
}
println("列表大小:$result")
// ------------------------------------
val builder = StringBuilder()
with(builder) {
append("Hello")
append(" ")
append("World")
}4. apply
- 用途:常用于初始化或配置对象。
- 语法特点:在 lambda 表达式中,使用
this指代对象,并且返回对象本身。 - 示例:
data class Car(var brand: String, var model: String, var year: Int)
val car = Car("", "", 0).apply {
brand = "Tesla"
model = "Model S"
year = 2025
}
println(car)5. also
- 用途:适用于在不改变对象本身的前提下执行额外的操作,比如日志记录或调试。
- 语法特点:在 lambda 表达式中,使用
it指代对象,并且返回对象本身。 - 示例:
val numbers = mutableListOf(1, 2, 3).also {
println("初始化列表:$it")
}
numbers.add(4)
println("更新后的列表:$numbers")
// -----------------------------------------
val file = File("data.txt").also {
println("Created file: ${it.name}")
check(it.canWrite()) // 附加验证
}6. 使用场景
1. **是否需要返回值**:
* 需要结果:let/run/with
* 需要原始对象:apply/also
1. **上下文访问方式**:
* 明确使用this:run/with/apply
* 需要显式名称:let/also
1. **典型场景**:
* 空安全:`?.let`
* 对象配置:apply
* 计算属性:run
* 链式调用:also
// 正确示例
val image = loadImage().apply {
resize(800, 600)
}.also {
log.debug("Processed image: $it")
}.let {
applyWatermark(it)
}更新: 2025-03-24 11:56:02
原文: https://www.yuque.com/dongpozhouzi-mshe3/zhm85g/wvfm0g2521rgpres