Kotlin中的Scope函数("域函数")是标准函数(let,also,run,apply,with),它们允许管理对象代码块的执行上下文。它们之间的区别在于:
it或通过this。| 函数 | this/it | 返回值 | 用途 |
|---|---|---|---|
| let | it | 结果 | 操作链,处理nullable,映射 |
| also | it | 对象 | 副作用,日志,调试 |
| run | this | 结果 | 计算,带返回值的初始化 |
| apply | this | 对象 | 对象配置,构建器 |
| with | this | 结果 | 与外部API工作,对象 "外部" |
示例:
let:如果对象为nullable,则很方便:val str: String? = "Text" str?.let { println(it.length) }
apply:对象设置:val paint = Paint().apply { color = Color.RED strokeWidth = 2f }
run:在对象上执行,返回结果:val length = "abcde".run { length }
with:用于与外部对象工作:val sb = StringBuilder() with(sb) { append("Hello, ") append("world!") toString() }
also:用于副作用(例如,日志):val list = mutableListOf(1, 2, 3) list.also { println("Before: $it") }.add(4)
it中创建对象的副本,修改对象的属性不太方便。this / it),对构建器很有用。with是普通函数,不是扩展。let和also之间有什么区别?
答案:
it,let返回lambda的结果,通常用于转换链,also返回原始对象,用于副作用(日志,调试),以避免干扰转换链。示例:
val result = listOf(1).also { println(it) }.map { it * 2 } // 结果 — List<Int>
故事
新手使用let来配置对象,以为这样可以“在链中”更改其状态。结果在配置块结束时得到的不是对象,而是lambda的结果(例如,什么都没有),导致DSL构建链被破坏。
故事
在编写处理nullable对象的代码时,使用了run而不是let,没有注意到返回值的不同。最终表达式的结果与预期不同,使得null出现在不该出现的地方——应用逻辑出现了问题。
故事
在一个大型构建器中,意外地对内部对象使用了with,期待扩展模式。由于with不是扩展函数,由多个with块构成的链条工作不正确,内部调用混淆并超出了当前对象的范围。不得不完全重写对象创建的层次结构。