Kotlin 2.1.0 入门教程(十)
if
表达式
if
是一个表达式,它会返回一个值。
不存在三元运算符(condition ? then : else
),因为 if
在这种场景下完全可以胜任。
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
表达式的分支可以是代码块。在这种情况下,代码块中的最后一个表达式就是该代码块的值。
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
如果使用 if
作为表达式,例如用于返回它的值或将它赋值给一个变量,那么 else
分支是必需的。
when
表达式和语句
when
是一种基于多个可能的值或条件运行代码的条件表达式。它类似于 Java
、C
等语言中的 switch
语句。
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
用于完成某个操作,而不会返回任何进一步使用的值。
// 表达式。
// 返回一个字符串,该字符串被赋值给变量 text。
val text = when (x) {
1 -> "x == 1"
2 -> "x == 2"
else -> "x is neither 1 nor 2"
}
// 语句。
// 不返回任何值,但会触发一个打印语句。
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> print("x is neither 1 nor 2")
}
可以使用带有或不带有对象的 when
。无论是否在 when
中使用对象,表达式或语句的行为都是相同的。我们建议在可能的情况下使用带有对象的 when
,因为它清晰地展示你在检查什么,使你的代码更易于阅读和维护。
// 带对象。
when (x) { ... }
// 不带对象。
when { ... }
根据你如何使用 when
,对于是否需要在分支中覆盖所有可能的情况有不同的要求。
如果你将 when
用作语句,你不需要覆盖所有可能的情况。在下面的例子中,并没有覆盖所有情况,因此当不匹配任何分支时,不会发生任何事情。但也不会出现错误:
val x = 3
when (x) {
// 并未覆盖所有情况。
1 -> print("x == 1")
2 -> print("x == 2")
}
在 when
语句中,各个分支的值会被忽略。就像 if
一样,每个分支可以是一个代码块,而代码块的值是块中最后一个表达式的值。
如果你将 when
用作表达式,那么你必须覆盖所有可能的情况,也就是说,它必须是穷尽的。第一个匹配分支的值将成为整个表达式的值。如果你没有覆盖所有情况,编译器会报错。
如果你的 when
表达式有一个对象,你可以使用 else
分支来确保覆盖所有可能的情况,但这并不是强制性的。例如,如果对象是一个布尔类型、枚举类、密封类,或者它们的可空类型,那么你可以不使用 else
分支来覆盖所有情况。例如:
enum class Bit {
ZERO, ONE
}
val numericValue = when (getRandomBit()) {
// 不需要 else 分支,因为所有可能的情况都已经被覆盖了。
Bit.ZERO -> 0
Bit.ONE -> 1
}
如果你的 when
表达式没有对象,那么你必须有一个 else
分支,否则编译器会报错。当没有其他分支条件被满足时,else
分支会被执行。例如:
val number = 5
val result = when {
number > 0 -> "Positive"
number < 0 -> "Negative"
// 必须有 else 分支,因为没有对象。
else -> "Zero"
}
when
表达式和语句提供了多种方法来简化代码、处理多个条件以及执行类型检查。
你可以通过在单行中用逗号分隔多个条件,为多个案例定义共同的行为。例如:
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")
}
你可以使用任意表达式(不仅仅是常量)作为分支条件。例如:
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")
}
在这个例子中,y
、y + 5
和 y - 5
都是作为分支条件的表达式。when
会根据 x
的值与这些表达式的结果进行比较,从而选择对应的分支。这种方式使得 when
的条件更加灵活,可以用于更复杂的逻辑判断。
你还可以通过 in
或 !in
关键字来检查一个值是否包含在某个范围或集合中:
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
关键字来检查一个值是否是某种特定类型。由于智能类型转换,你可以直接访问该类型的成员函数和属性,而无需额外的检查。
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
你可以将 when
用作 if-else if
链的替代品。如果没有对象,分支条件就是布尔表达式。第一个条件为 true
的分支会被执行:
when {
x.isOdd() -> print("x is odd")
y.isEven() -> print("y is even")
else -> print("x + y is odd")
}
你可以通过以下语法在变量中捕获对象:
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
在 when
表达式或语句的主体中引入的变量的作用域仅限于该 when
表达式或语句的内部。
when
表达式中的守护条件
守护条件是一个实验性功能,可能会随时发生变化。
守护条件允许你在 when
表达式的分支中包含多个条件,从而使复杂的控制流程更加明确和简洁。你可以在带有对象的 when
表达式或语句中使用守护条件。
要在分支中包含守护条件,请将其放在主条件之后,并用 if
分隔。
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
的功能。
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")
}
你可以在一个分支中通过使用布尔运算符 &&
或 ||
组合多个守护条件。为了避免混淆,请使用括号将布尔表达式括起来。
when (animal) {
is Animal.Cat if (!animal.mouseHunter && animal.hungry) -> feedCat()
}
你可以在任何带有对象的 when
表达式或语句中使用守护条件,但有一个例外,当你的条件是通过逗号分隔的多个值时,例如 0, 1 -> print("x == 0 or x == 1")
,这种情况下不能使用守护条件。
要在命令行界面中启用守护条件,运行以下命令:
kotlinc -Xwhen-guards main.kt
要在 Gradle
中启用守护条件,将以下代码添加到 build.gradle.kts
文件中:
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xwhen-guards")
}
}