with 是 Kotlin 的核心作用域函数之一,专注于在对象上下文中批量执行操作并返回计算结果,通过隐式 this 访问对象成员,适用于需集中处理同一对象属性的场景14。
一、语法与核心特性
1. 函数签名
inline fun <T, R> with(receiver: T, block: T.() -> R): R
-
参数:
receiver:任意类型的对象(非空)。block:带接收者的 Lambda(T.() -> R),隐式通过this访问对象成员。
-
返回值:Lambda 最后一个表达式的结果(类型为
R)。
2. 核心机制
- 隐式上下文:Lambda 内直接访问对象的属性和方法,无需显式
this18。 - 集中操作:在同一代码块中连续调用对象的多项方法或设置属性,代码更紧凑46。
- 内联优化:编译时直接将 Lambda 内容插入调用处,避免性能损耗67。
二、典型应用场景
1. 批量操作对象属性
对同一对象执行多个方法或属性设置,替代冗余的重复对象名书写:
val person = Person("Alice", 25)
val info = with(person) {
name = "Bob"
age += 1
"姓名: $name, 年龄: $age" // 返回最终计算结果
}
println(info) // 输出:姓名: Bob, 年龄: 26
- 优势:简化对象操作的代码层级,提升可读性48。
2. 构建复杂字符串或集合
集中调用 StringBuilder 或集合的方法生成结果:
val list = listOf("a", "b", "c")
val result = with(StringBuilder()) {
append("start\n")
list.forEach { append("$it\n") }
append("end")
toString() // 返回拼接后的字符串
}
println(result)
// 输出:
// start
// a
// b
// c
// end
- 适用性:适用于需要链式调用的临时对象构建场景8。
3. 替代临时变量
在需要表达式的位置直接操作对象,避免中间变量:
val totalLength = with(getFileList()) {
sumOf { it.length } // 计算文件列表中所有文件名的总长度
}
三、与其他作用域函数对比
| 函数 | 语法形式 | 返回值 | 典型场景 |
|---|---|---|---|
with | with(obj) { ... } | Lambda 结果 | 集中操作非空对象的属性或方法 |
run | obj.run { ... } | Lambda 结果 | 对象上下文计算与初始化结合 |
apply | obj.apply { ... } | 对象本身 | 对象初始化与属性批量配置 |
let | obj?.let { ... } | Lambda 结果 | 空安全检查与数据转换 |
关键区别:
with是非扩展函数,需显式传入对象参数,而run和apply是扩展函数16。with与run均返回 Lambda 结果,但with更强调对已有对象的集中操作,而run支持链式调用与临时作用域创建38。
四、注意事项
-
非空对象要求
with需显式传入非空对象,若对象可能为空需结合安全调用符(?.)或其他空检查逻辑处理17。 -
返回值明确性
需确保 Lambda 的最后一行表达式为目标结果,避免意外返回Unit:// 错误示例:未明确返回值 val invalid = with(StringBuilder()) { append("content") // 最后一行返回 Unit }- 修正:显式添加返回值(如
toString())8。
- 修正:显式添加返回值(如
总结
with 的核心价值在于集中处理非空对象的属性与方法调用,通过隐式上下文访问和灵活返回值简化代码结构,适用于需在同一作用域内批量操作对象且生成计算结果的场景