Kotlin 中作用域函数 let、with、run、also、apply 的核心使用指南

以下是 Kotlin 中作用域函数 let、with、run、also、apply 的核心使用指南,结合其特性、适用场景及代码示例整理而成:


🧩 ​一、作用域函数核心对比​

函数 上下文对象引用 返回值 典型场景
​**let**​ it Lambda 结果 空安全操作、数据转换、链式处理中间结果
​**run**​ this Lambda 结果 对象配置与计算混合、替代 with(扩展函数形式)、链式空安全处理
​**with**​ this Lambda 结果 集中操作非空对象的多属性/方法(需显式传入对象)
​**apply**​ this 对象本身 对象初始化配置(类似 Builder 模式)、多属性设置
​**also**​ it 对象本身 附加操作(如日志、验证)、链式调用中插入副作用

💡 ​选择关键​:

  • 需返回对象本身 → apply/also;需返回计算结果 → let/run/with。
  • 上下文引用偏好 → this(run/with/apply)更简洁;it(let/also)避免命名冲突。
  • 空安全 → ?.let 或 ?.run 优先。

⚙️ ​二、分函数详解与示例​

1. ​**let:空安全转换与作用域隔离**​

  • ​场景​:处理可空对象、数据转换、链式操作中间处理。

  • ​示例​:

    kotlin 复制代码
    val name: String? = "Kotlin"
    val length = name?.let { 
        println("Processing: $it")  // 输出:Processing: Kotlin
        it.length                   // 返回结果
    } ?: 0                         // 提供默认值

    ​典型链式转换​:

    ini 复制代码
    val numbers = listOf(1, 2, 3)
    val doubled = numbers
        .filter { it > 1 }
        .let { it.map { num -> num * 2 } }  // [4, 6]

2. ​**run:对象配置与计算混合**​

  • ​场景 ​:对象初始化+结果计算、替代 with(扩展函数形式)、临时作用域创建。

  • ​示例​:

    kotlin 复制代码
    // 扩展函数形式(配置对象并返回结果)
    val personInfo = Person("Alice", 25).run {
        name = "Bob"           // 直接修改属性(this 可省略)
        age += 1
        "Name: $name, Age: $age"  // 返回字符串
    }  // 输出:Name: Bob, Age: 26
    
    // 非扩展形式(替代临时变量)
    val fullName = run {
        val firstName = "John"
        val lastName = "Doe"
        "$firstName $lastName"     // 返回拼接结果
    }

3. ​**with:集中操作非空对象**​

  • ​场景​:对同一对象执行多步操作(无需重复写对象名)。

  • ​示例​:

    kotlin 复制代码
    val person = Person("Bob", 25)
    val info = with(person) {
        age = 26                   // 直接访问属性
        "Name: $name, Age: $age"   // 返回结果
    }

4. ​**apply:对象初始化配置**​

  • ​场景​:构建对象时批量设置属性(返回自身,支持链式)。

  • ​示例​:

    ini 复制代码
    val person = Person().apply {
        name = "Charlie"
        age = 28
        address = "Paris"
    }  // 返回已配置的 Person 对象

5. ​**also:链式调用附加操作**​

  • ​场景​:日志记录、数据验证等副作用操作(不影响对象本身)。

  • ​示例​:

    scss 复制代码
    mutableListOf(1, 2, 3)
        .also { println("初始列表: $it") }  // 输出:初始列表: [1, 2, 3]
        .add(4)

🛠️ ​三、进阶技巧与避坑指南​

  1. ​链式组合​:

    • apply + also:初始化后记录日志

      scss 复制代码
      val file = File("data.txt").apply { 
          createNewFile() 
      }.also { println("创建文件: ${it.path}") }
    • let + run:空安全转换后继续操作

      scss 复制代码
      user?.let { it.validate() }?.run { process(this) }
  2. ​空安全优先策略​:

    • 可空对象操作 → ?.let {} ?: default
    • 避免 apply/also 在可空对象上直接调用(需手动判空)。
  3. ​性能优化​:

    • 所有作用域函数均为 inline,无运行时开销(编译期内联优化)。

💎 ​四、总结选择流程图​

graph TD A{NeedReturnSelf} A -->|Yes| B{Require This} B -->|Yes| C[apply] B -->|No| D[also] A -->|No| E{NeedNullSafe} E -->|Yes| F[let] E -->|No| G{RequireExtension} G -->|Yes| H[run] G -->|No| I[with]

通过明确操作目标 ​(配置、转换、副作用)和上下文需求​(空安全、链式、作用域隔离),可精准选用最合适的函数。

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui