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

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


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

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

💡 ​选择关键​:

  • 需返回对象本身 → apply/also;需返回计算结果 → let/run/with
  • 上下文引用偏好 → thisrun/with/apply)更简洁;itlet/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]

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

相关推荐
我是好小孩2 小时前
Android-侧边导航栏的使用
android·gitee
吗喽对你问好2 小时前
安卓基础布局核心知识点整理
android·gitee
安卓开发者2 小时前
Android Material Components 全面解析:打造现代化 Material Design 应用
android
教程分享大师2 小时前
带root权限_中国移动创维DT541_S905L3融合机器改机顶盒刷机教程 当贝纯净版安卓9.0系统线刷包 刷机包
android
wuk9982 小时前
Android:UI:Drawable:View/ImageView与Drawable
android·ui
旋风菠萝4 小时前
设计模式---单例
android·java·开发语言
whysqwhw5 小时前
Android Jetpack 中 ViewModel 的全面解析
android
2501_916007478 小时前
iPhone查看App日志和系统崩溃日志的完整实用指南
android·ios·小程序·https·uni-app·iphone·webview
稻草人不怕疼8 小时前
Android 渲染机制小结
android