Kotlin 又要加语法糖了:这次轮到 if-else

0 阅读4分钟

cover.png

Kotlin 一直在改进。

Kotlin 2.5.0-Beta2 中提供了三个实验性的标准库函数(已在 2.5.0-Beta1 的发布记录中列出):

  • onTrue()
  • onFalse()
  • ifOrNull()

它们可以减少重复的 if-else 表达式,让一些常见的 Kotlin 写法更容易读懂。

我发现现代语言在语法糖上有个小趋势,就是支持更多链式调用的写法。

下面用 Android 中的常见场景说明它们的用法。

1. onTrue() 和 onFalse()

它们做什么

假设我们需要根据一个布尔结果执行操作。比如:

  • 登录成功,记录成功日志。
  • 登录失败,记录错误日志。
  • 支付成功,触发埋点事件。

通常,我们会写一个 if-else 代码块来处理。

以前:使用 if-else

有一个 Android 登录页面。验证用户凭据后,我们希望记录认证成功还是失败。

fun authenticate(user: User, token: String): Boolean {
    val isAuthenticated = verifyToken(user.email, token)
    if (isAuthenticated) {
        logSuccess("Login successful")
    } else {
        logFailure("Login failed")
    }
    return isAuthenticated
}

这段代码没有问题,也是我们已经很熟悉的写法。

现在:使用 onTrue() 和 onFalse()

@OptIn(ExperimentalStdlibApi::class)
fun authenticate(user: User, token: String): Boolean =
    verifyToken(user.email, token)
        .onTrue {
            logSuccess("Login successful")
        }
        .onFalse {
            logFailure("Login failed")
        }

是不是有点像 Result 的处理方法?

怎么理解

onTrue():

  • 只有布尔值为 true 时,才执行 lambda。
  • 值为 false 时,不执行任何操作。
  • 返回原来的布尔值。

onFalse():

  • 只有布尔值为 false 时,才执行 lambda。
  • 值为 true 时,不执行任何操作。
  • 返回原来的布尔值。

例如:

@OptIn(ExperimentalStdlibApi::class)
val result = true
    .onTrue { println("Success") }
    .onFalse { println("Failure") }
println(result) // true

其实很简单!

什么时候适合用?这取决于你的喜好和需求,不过可以参考下面几个场景:

  • 记录成功或失败日志。
  • 触发埋点事件。
  • 显示轻量提示。
  • 根据结果执行回调。

如果只是根据 Boolean 值执行操作,并保留原来的布尔结果,就可以考虑这两个函数。

这两个函数适合处理副作用,不会把布尔值转换成其他值。

2. ifOrNull()

它做什么

有时,我们只想在条件成立时返回一个值,条件不成立时返回 null。

比如用户资料页:用户可能填写了电话号码,也可能没有。只有存在联系信息时,我们才希望提供电话号码。

以前:使用 if-else

val phoneNumber = if (user.hasContactInfo) {
    user.phoneNumber
} else {
    null
}

在 Kotlin 2.5.0-Beta2 中,可以用一种更短的写法。

现在:使用 ifOrNull()

@OptIn(ExperimentalStdlibApi::class)
val phoneNumber = ifOrNull(user.hasContactInfo) {
    user.phoneNumber
}

怎么理解

可以把 ifOrNull() 理解为一个根据条件提供值的函数:

  • 条件为 true 时,执行 lambda 并返回它的结果。
  • 条件为 false 时,返回 null。
  • 条件为 false 时,不会执行 lambda。

实际场景:映射 API 响应

假设在 Android 开发中,一个 API 返回用户资料。有些用户有联系信息,有些没有。

data class User(
    val name: String,
    val hasContactInfo: Boolean,
    val phoneNumber: String?
)

我们希望只在存在联系信息时,才为资料页准备要显示的电话号码。

@OptIn(ExperimentalStdlibApi::class)
fun getDisplayPhoneNumber(user: User): String? {
    return ifOrNull(user.hasContactInfo) {
        user.phoneNumber ?: "No phone number"
    }
}

这样:

  • hasContactInfo 为 true 时,执行 lambda,返回电话号码或兜底文案。
  • hasContactInfo 为 false 时,结果为 null。

映射 API 响应、准备可选的 UI 数据、创建 DTO 时,都可以用到这种写法。

3. 能力速查

函数作用返回值
onTrue()值为 true 时执行操作原来的布尔值
onFalse()值为 false 时执行操作原来的布尔值
ifOrNull()条件为 true 时执行代码块代码块的结果或 null

4. 仍处于实验阶段

在 Kotlin 2.5.0-Beta2 中,这些函数仍是实验性 API。使用时需要显式选择启用:

@OptIn(ExperimentalStdlibApi::class)

也可以在项目中通过编译器选项 -opt-in=kotlin.ExperimentalStdlibApi 统一启用。

本文以 Beta2 版本为例。在生产代码中采用这些 API 前,请先查看最新的 Kotlin 文档,确认它们的状态和用法。

5. 一点想法

这三个函数改动不大,但让常见的 Kotlin 写法更容易表达意图。遇到重复的条件代码块时,可以直接写出要做的事:

  • 成功时执行操作,用 onTrue()。
  • 失败时执行操作,用 onFalse()。
  • 根据条件返回值,用 ifOrNull()。

当然,代码行数并不是唯一的目标,更重要的是让代码容易理解和维护。

还有一点,正如我开头提到的那样,现代语言越来越支持链式调用。写完一个函数调用后,我可以自然地继续使用 . 调用下一个函数去处理结果。在这类场景下,相比使用 if-else,这样的写法确实更简洁,写起来也更流畅。

可能这也是为什么曾经 RxJava 如此流行的原因之一吧。