Kotlin: run, let, apply, also, with — 何时使用?完整解析与示例
你好,朋友!如果你正在学习 Kotlin 并希望编写简洁、优雅的代码,那么迟早会遇到五个神奇的函数:run、let、apply、also 和 with。它们是作用域函数——允许你在对象的上下文中执行代码,极大地简化了开发工作。
但问题在于:许多初学者(甚至是有经验的开发者)会混淆何时使用哪个函数。这个问题是 Stack Overflow 上最热门的问题之一,今天我们将一劳永逸地弄清楚如何避免错误。我们不仅会列出规则——还会展示来自实际项目的真实示例,你可以立即在自己的项目中使用它们。
什么是作用域函数,为什么需要它们?
作用域函数是为对象创建临时作用域的函数。在这个作用域内,你可以通过 it 或 this 访问对象。它们之间的主要区别在于如何返回结果以及如何引用上下文。
以下是一个简明的速查表,我们将用示例来填充它:
let— 上下文:it,返回:lambda 表达式的结果。用于非空检查和调用链。run— 上下文:this,返回:lambda 表达式的结果。通用函数,常用于初始化和计算。apply— 上下文:this,返回:对象本身。非常适合配置对象的属性。also— 上下文:it,返回:对象本身。适合执行额外操作(日志记录、检查)。with— 非扩展函数,上下文:this,返回:lambda 表达式的结果。方便对同一对象进行分组调用,而无需创建新对象。
记住主要规则:函数的选择取决于你需要返回对象还是结果,以及你希望如何引用上下文(通过 it 还是 this)。
1. let — 安全链的王者
let 是你处理可空对象时的最佳伙伴。它仅在对象不为 null 时执行代码。上下文通过 it 传递。
示例:安全转换
val name: String? = "安德烈"// 不使用 let:if (name != null) { println("名字长度:${name.length}")}
// 使用 let(更优雅):name?.let { println("名字长度:${it.length}")}let 也非常适合操作链。例如,当你需要将一个对象转换为另一个对象时:
val numbers = listOf(1, 2, null, 4, null, 6)val nonNullSquared = numbers .mapNotNull { it } .let { list -> list.map { it * it } }println(nonNullSquared) // [1, 4, 16, 36]何时使用 let:
- 空值检查(最常见的用例)。
- 将一个值转换为另一个值。
- 对结果执行一系列操作。
2. apply — 简洁的构造器
apply 返回对象本身,而在 lambda 内部上下文是 this。这是在使用前配置对象的理想工具。忘掉冗长的 set 代码块吧!
示例:配置 View(Android)或 data class
data class User(var name: String = "", var age: Int = 0)
val user = User().apply { name = "玛丽亚" age = 25}println(user) // User(name=玛丽亚, age=25)
// 更酷的是——配置 TextView:val textView = TextView(context).apply { text = "你好,Kotlin!" textSize = 18f setTextCo