Kotlin的let、with、run、apply、also函数简介

6 阅读1分钟

Kotlin 里有五个“看似相似、实则各有门派”的函数:let、with、run、apply、also。

它们是 Kotlin 官方定义的“标准函数(Standard Functions)”,

可是在面试中,它们也是让人最头疼的考点之一:

“run 和 apply 有什么区别?” “什么时候用 let 比 also 更合适?” “with 为什么几乎不推荐用了?”

一、let — 最常用的空安全与链式利器

定义

inline fun <T, R> T.let(block: (T) -> R): R

把当前对象(this)作为参数 it 传入 block 中执行,返回 block 的结果。

使用场景 1:空安全

user?.let {
    println("User name: ${it.name}")
}

只有在 user 非空时才执行,防止空指针异常(NullPointerException)。

使用场景 2:链式操作

val result = text?.let { it.trim() }?.let { it.uppercase() }

可连续调用,简洁优雅。

使用场景 3:临时作用域

val length = "Kotlin".let {
    println("String is: $it")
    it.length
}

减少全局变量污染。

二、with — 对同一对象执行多操作的老派绅士

定义

inline fun <T, R> with(receiver: T, block: T.() -> R): R

with 是一个普通函数,不是扩展函数。需要把对象作为参数传入。

使用场景:连续操作一个对象

with(paint) {
    color = Color.RED
    style = Paint.Style.FILL
    strokeWidth = 3f
}

DSL 风格构建

val text = with(StringBuilder()) {
    append("Hello, ")
    append("Kotlin!")
    toString()
}

三、run — 既能执行又能返回的多面手

定义

inline fun <T, R> T.run(block: T.() -> R): R

run 的语义是“执行一段代码,并返回结果”。常用于“初始化 + 返回值”。

使用场景 1:对象初始化 + 返回结果

val config = Config().run {
    setMode("Dark")
    setSize(1080, 1920)
    this // 返回整个对象
}

使用场景 2:空安全执行逻辑

val len = text?.run {
    println("Length: $length")
    length
} ?: 0

四、apply — 对象初始化的终极神器

定义

inline fun <T> T.apply(block: T.() -> Unit): T

apply 与 run 的区别是:返回对象本身。

 使用场景:创建并配置对象

val dialog = AlertDialog.Builder(context).apply {
    setTitle("Warning")
    setMessage("Are you sure?")
    setPositiveButton("Yes", null)
}.create()

连贯初始化

val json = JSONObject().apply {
    put("name", "Kotlin")
    put("version", "1.9")
}.toString()

句话理解: apply 用于初始化对象,返回对象自身。

五、also — 调试与副作用专用的隐形帮手

定义

inline fun <T> T.also(block: (T) -> Unit): T

与 apply 类似,但 also 使用 it 而不是 this。

使用场景 1:打印调试

val user = User("Tom", 18).also {
    println("Created user: $it")
}

使用场景 2:链式调用插入副作用

val list = mutableListOf(1, 2, 3)
    .also { println("Before add: $it") }
    .apply { add(4) }
    .also { println("After add: $it") }

一句话理解: also 用于链式副作用(打印、调试、记录),返回对象自身。