Kotlin 2.1.0 入门教程(十)

if 表达式

if 是一个表达式,它会返回一个值。

不存在三元运算符(condition ? then : else),因为 if 在这种场景下完全可以胜任。

kotlin 复制代码
var max = a

if (a < b) max = b

if (a > b) {
    max = a
} else {
    max = b
}

max = if (a > b) a else b

val maxLimit = 1

val maxOrLimit = if (maxLimit > a) maxLimit else if (a > b) a else b

if 表达式的分支可以是代码块。在这种情况下,代码块中的最后一个表达式就是该代码块的值。

kotlin 复制代码
val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}

如果使用 if 作为表达式,例如用于返回它的值或将它赋值给一个变量,那么 else 分支是必需的。

when 表达式和语句

when 是一种基于多个可能的值或条件运行代码的条件表达式。它类似于 JavaC 等语言中的 switch 语句。

kotlin 复制代码
val x = 2

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> print("x is neither 1 nor 2")
}

when 会依次将它的参数与所有分支的条件进行匹配,直到某个分支的条件被满足为止。

你可以以几种不同的方式使用 when。首先,你可以将 when 用作表达式或语句。作为表达式,when 会返回一个值,供你在代码中后续使用。作为语句,when 用于完成某个操作,而不会返回任何进一步使用的值。

kotlin 复制代码
// 表达式。
// 返回一个字符串,该字符串被赋值给变量 text。
val text = when (x) {
    1 -> "x == 1"
    2 -> "x == 2"
    else -> "x is neither 1 nor 2"
}
kotlin 复制代码
// 语句。
// 不返回任何值,但会触发一个打印语句。
when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> print("x is neither 1 nor 2")
}

可以使用带有或不带有对象的 when。无论是否在 when 中使用对象,表达式或语句的行为都是相同的。我们建议在可能的情况下使用带有对象的 when,因为它清晰地展示你在检查什么,使你的代码更易于阅读和维护。

kotlin 复制代码
// 带对象。
when (x) { ... }
kotlin 复制代码
// 不带对象。
when { ... }

根据你如何使用 when,对于是否需要在分支中覆盖所有可能的情况有不同的要求。

如果你将 when 用作语句,你不需要覆盖所有可能的情况。在下面的例子中,并没有覆盖所有情况,因此当不匹配任何分支时,不会发生任何事情。但也不会出现错误:

kotlin 复制代码
val x = 3
when (x) {
    // 并未覆盖所有情况。
    1 -> print("x == 1")
    2 -> print("x == 2")
}

when 语句中,各个分支的值会被忽略。就像 if 一样,每个分支可以是一个代码块,而代码块的值是块中最后一个表达式的值。

如果你将 when 用作表达式,那么你必须覆盖所有可能的情况,也就是说,它必须是穷尽的。第一个匹配分支的值将成为整个表达式的值。如果你没有覆盖所有情况,编译器会报错。

如果你的 when 表达式有一个对象,你可以使用 else 分支来确保覆盖所有可能的情况,但这并不是强制性的。例如,如果对象是一个布尔类型、枚举类、密封类,或者它们的可空类型,那么你可以不使用 else 分支来覆盖所有情况。例如:

kotlin 复制代码
enum class Bit {
    ZERO, ONE
}

val numericValue = when (getRandomBit()) {
    // 不需要 else 分支,因为所有可能的情况都已经被覆盖了。
    Bit.ZERO -> 0
    Bit.ONE -> 1
}

如果你的 when 表达式没有对象,那么你必须有一个 else 分支,否则编译器会报错。当没有其他分支条件被满足时,else 分支会被执行。例如:

kotlin 复制代码
val number = 5

val result = when {
    number > 0 -> "Positive"
    number < 0 -> "Negative"
    // 必须有 else 分支,因为没有对象。
    else -> "Zero" 
}

when 表达式和语句提供了多种方法来简化代码、处理多个条件以及执行类型检查。

你可以通过在单行中用逗号分隔多个条件,为多个案例定义共同的行为。例如:

kotlin 复制代码
val x = 2

when (x) {
    1, 2, 3 -> println("x is 1, 2, or 3")
    4, 5, 6 -> println("x is 4, 5, or 6")
    else -> println("x is not in the range 1 to 6")
}

你可以使用任意表达式(不仅仅是常量)作为分支条件。例如:

kotlin 复制代码
val x = 5
val y = 10

when (x) {
    y -> println("x is equal to y")
    y + 5 -> println("x is equal to y + 5")
    y - 5 -> println("x is equal to y - 5")
    else -> println("x is not equal to y, y + 5, or y - 5")
}

在这个例子中,yy + 5y - 5 都是作为分支条件的表达式。when 会根据 x 的值与这些表达式的结果进行比较,从而选择对应的分支。这种方式使得 when 的条件更加灵活,可以用于更复杂的逻辑判断。

你还可以通过 in!in 关键字来检查一个值是否包含在某个范围或集合中:

kotlin 复制代码
when (x) {
    in 1 .. 10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10 .. 20 -> print("x is outside the range")
    else -> print("none of the above")
}

此外,你可以通过 is!is 关键字来检查一个值是否是某种特定类型。由于智能类型转换,你可以直接访问该类型的成员函数和属性,而无需额外的检查。

kotlin 复制代码
fun hasPrefix(x: Any) = when(x) {
    is String -> x.startsWith("prefix")
    else -> false
}

你可以将 when 用作 if-else if 链的替代品。如果没有对象,分支条件就是布尔表达式。第一个条件为 true 的分支会被执行:

kotlin 复制代码
when {
    x.isOdd() -> print("x is odd")
    y.isEven() -> print("y is even")
    else -> print("x + y is odd")
}

你可以通过以下语法在变量中捕获对象:

kotlin 复制代码
fun Request.getBody() =
    when (val response = executeRequest()) {
        is Success -> response.body
        is HttpError -> throw HttpException(response.status)
    }

when 表达式或语句的主体中引入的变量的作用域仅限于该 when 表达式或语句的内部。

when 表达式中的守护条件

守护条件是一个实验性功能,可能会随时发生变化。

守护条件允许你在 when 表达式的分支中包含多个条件,从而使复杂的控制流程更加明确和简洁。你可以在带有对象的 when 表达式或语句中使用守护条件。

要在分支中包含守护条件,请将其放在主条件之后,并用 if 分隔。

kotlin 复制代码
sealed interface Animal {
    data class Cat(val mouseHunter: Boolean) : Animal
    data class Dog(val breed: String) : Animal
}

fun feedAnimal(animal: Animal) {
    when (animal) {
        is Animal.Dog -> feedDog()
        is Animal.Cat if !animal.mouseHunter -> feedCat()
        else -> println("Unknown animal")
    }
}

在一个 when 表达式中,你可以同时使用带有守护条件和没有守护条件的分支。带有守护条件的分支中的代码只有在主条件和守护条件都为 true 时才会执行。如果主条件不满足,守护条件不会被评估。

如果你在没有 else 分支的 when 语句中使用守护条件,并且没有任何条件匹配,那么没有任何分支会被执行。

否则,如果你在没有 else 分支的 when 表达式中使用守护条件,编译器会要求你声明所有可能的情况,以避免运行时错误。

此外,守护条件还支持 else if 的功能。

kotlin 复制代码
when (animal) {
    // 检查 animal 是否是 Dog。
    is Animal.Dog -> feedDog()

    // 检查 animal 是否是 Cat 并且不是 mouseHunter。
    is Animal.Cat if !animal.mouseHunter -> feedCat()

    // 如果前面的条件都不匹配,并且 animal.eatsPlants 为 true,则此。
    else if animal.eatsPlants -> giveLettuce()

    // 如果前面的条件都不匹配,则此。
    else -> println("Unknown animal")
}

你可以在一个分支中通过使用布尔运算符 &&|| 组合多个守护条件。为了避免混淆,请使用括号将布尔表达式括起来。

kotlin 复制代码
when (animal) {
    is Animal.Cat if (!animal.mouseHunter && animal.hungry) -> feedCat()
}

你可以在任何带有对象的 when 表达式或语句中使用守护条件,但有一个例外,当你的条件是通过逗号分隔的多个值时,例如 0, 1 -> print("x == 0 or x == 1"),这种情况下不能使用守护条件。

要在命令行界面中启用守护条件,运行以下命令:

bash 复制代码
kotlinc -Xwhen-guards main.kt

要在 Gradle 中启用守护条件,将以下代码添加到 build.gradle.kts 文件中:

kotlin 复制代码
kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xwhen-guards")
    }
}
相关推荐
Meteors.42 分钟前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton1 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw5 小时前
安卓图片性能优化技巧
android
风往哪边走6 小时前
自定义底部筛选弹框
android
Yyyy4826 小时前
MyCAT基础概念
android
Android轮子哥7 小时前
尝试解决 Android 适配最后一公里
android
雨白8 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android
风往哪边走9 小时前
自定义仿日历组件弹框
android
没有了遇见9 小时前
Android 外接 U 盘开发实战:从权限到文件复制
android
Monkey-旭10 小时前
Android 文件存储机制全解析
android·文件存储·kolin