以下是 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
:空安全转换与作用域隔离**
-
场景:处理可空对象、数据转换、链式操作中间处理。
-
示例:
kotlinval name: String? = "Kotlin" val length = name?.let { println("Processing: $it") // 输出:Processing: Kotlin it.length // 返回结果 } ?: 0 // 提供默认值
典型链式转换:
inival 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
:集中操作非空对象**
-
场景:对同一对象执行多步操作(无需重复写对象名)。
-
示例:
kotlinval person = Person("Bob", 25) val info = with(person) { age = 26 // 直接访问属性 "Name: $name, Age: $age" // 返回结果 }
4. **apply
:对象初始化配置**
-
场景:构建对象时批量设置属性(返回自身,支持链式)。
-
示例:
inival person = Person().apply { name = "Charlie" age = 28 address = "Paris" } // 返回已配置的 Person 对象
5. **also
:链式调用附加操作**
-
场景:日志记录、数据验证等副作用操作(不影响对象本身)。
-
示例:
scssmutableListOf(1, 2, 3) .also { println("初始列表: $it") } // 输出:初始列表: [1, 2, 3] .add(4)
🛠️ 三、进阶技巧与避坑指南
-
链式组合:
-
apply
+also
:初始化后记录日志scssval file = File("data.txt").apply { createNewFile() }.also { println("创建文件: ${it.path}") }
-
let
+run
:空安全转换后继续操作scssuser?.let { it.validate() }?.run { process(this) }
-
-
空安全优先策略:
- 可空对象操作 →
?.let {} ?: default
- 避免
apply
/also
在可空对象上直接调用(需手动判空)。
- 可空对象操作 →
-
性能优化:
- 所有作用域函数均为
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]
通过明确操作目标 (配置、转换、副作用)和上下文需求(空安全、链式、作用域隔离),可精准选用最合适的函数。