
从 2.1.0
版本开始,你可以在带有主题的 when
表达式或语句(when (subject)
)中使用守护条件。
守护条件允许你为 when
表达式的各个分支设置多个条件,这使得复杂的控制流更加清晰简洁,同时也简化了代码结构。
因为该特性在 2.1.0
版本还是 preview 阶段,所以需要启用此特性:

Kotlin
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xwhen-guards")
}
}
在完成如上的设置之后,我们便可以使用守卫特性了。
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 -> { println("I eat ${animal.breed}") }
// 同时带有主要条件和守护条件的分支
is Animal.Cat if !animal.mouseHunter -> { println("I am a pet eat cat food") }
// 如果上述条件均不匹配
is Animal.Cat -> println("I eat mouse")
}
}
fun main() {
feedAnimal(Animal.Cat(true))
feedAnimal(Animal.Cat(false))
feedAnimal(Animal.Dog("Meat"))
}
// Output
// I eat mouse
// I am a pet eat cat food
// I eat Meat
在单个 when
表达式中,你可以组合带有和不带有守护条件的分支。只有当主要条件和守卫条件都为真时,带有守护条件的分支中的代码才会运行。如果主要条件不匹配,则不会计算守护条件。此外,守护条件支持 else if
。
上述代码中,最后一个语句是 is Animal.Cat
,此时你可以不用写 else
语句,因为编译器会检查你的 when
表达式是否穷尽。
为什么不用 && ?
有的编程语言使用了 &&
作为守卫表达式的连接符,Kotlin 此处使用了 if
,为什么呢?
Kotlin
var a = 10
when {
a < 100 && a > 0 -> {
println("under 100")
}
else -> {
println("others")
}
}
Kotlin 在无主题的 when
表达式中,判断条件就是使用 &&
作为连接符的,同时,在守卫条件中,if
表达式如果有多个条件,也需要使用 &&
或者 ||
:
Kotlin
var a = 10
when(a) {
is Long if (a < 100 && a > 0) -> {
println("under 100")
}
else -> {
println("others")
}
}
如果 Kotlin
选择 &&
作为守卫的连接符,那么在编写多条件时,可读性就会大大降低,也不利于理解。