作用域函数(Scope Functions)是Kotlin标准库中的特殊函数,允许在对象上下文中执行代码块。核心作用包括:

  • 简化对象操作
  • 增强代码可读性
  • 减少临时变量
  • 链式调用支持

五大作用域函数对比

函数上下文引用返回值扩展函数典型应用场景
letitlambda结果非空对象处理/数据转换
runthislambda结果对象初始化/计算返回值
withthislambda结果对象多操作/无返回值操作
applythis对象本身对象配置/属性批量设置
alsoit对象本身附加操作/日志记录

三、详细用法解析

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


相关笔记