密封层次结构中的穷尽式 when
编写覆盖每个密封变体的完整 when 表达式。
密封层次结构中的穷尽式 when 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。
完备的条件表达式
作为表达式使用的 when 表达式必须是完备的——必须处理每个可能的值。密封层次结构可以让编译器为您验证这一点。
开放类型上的不完备条件表达式
对于普通类,编译器无法检查所有子类型,因此需要一个 else 分支。
open class Shape
class Circle : Shape()
class Square : Shape()
fun describe(s: Shape) = when (s) {
is Circle -> "circle"
is Square -> "square"
else -> "unknown" // required
}
fun main() { println(describe(Circle())) }密封类型上的完备条件表达式
对于密封类,编译器知道所有子类型。如果每种情况都已覆盖,则无需 else 分支。
sealed class Result
class Success(val value: Int) : Result()
class Failure(val msg: String) : Result()
fun describe(r: Result) = when (r) {
is Success -> "ok: ${r.value}"
is Failure -> "err: ${r.msg}"
}
fun main() {
println(describe(Success(42)))
println(describe(Failure("nope")))
}密封接口
即使类需要多重继承,密封接口也能提供完备性检查。
sealed interface Animal
class Dog : Animal
class Cat : Animal
fun speak(a: Animal) = when (a) {
is Dog -> "woof"
is Cat -> "meow"
}
fun main() {
println(speak(Dog()))
println(speak(Cat()))
}分支中的智能类型转换
在每个 is 分支中,Kotlin 会将变量智能转换为特定类型——无需手动转换。
sealed class Event
data class Click(val x: Int, val y: Int) : Event()
data class Key(val char: Char) : Event()
fun handle(e: Event) = when (e) {
is Click -> "clicked at (${e.x},${e.y})" // smart-cast
is Key -> "key=${e.char}"
}
fun main() {
println(handle(Click(10, 20)))
println(handle(Key('A')))
}遗漏一种情况
如果稍后添加新的变体,那么所有仍将密封类型作为表达式使用的完备 when 都会无法通过编译——这是非常出色的安全保障。
sealed class Status
object Idle : Status()
object Running : Status()
// If we add object Done : Status(), every exhaustive when must update.
fun text(s: Status): String = when (s) {
is Idle -> "idle"
is Running -> "running"
}
fun main() { println(text(Idle)) }密封类型与数据类
一种常见模式是:使用数据类作为密封层次结构的变体。
sealed class UiState {
object Loading : UiState()
data class Success(val data: List<String>) : UiState()
data class Error(val message: String) : UiState()
}
fun render(state: UiState) = when (state) {
UiState.Loading -> "loading..."
is UiState.Success -> "got ${state.data.size} items"
is UiState.Error -> "error: ${state.message}"
}
fun main() {
println(render(UiState.Loading))
println(render(UiState.Success(listOf("a", "b"))))
println(render(UiState.Error("404")))
}将条件表达式用作语句
当 when 用作语句而不是表达式时,不要求它完备。但这样会失去安全保障。
sealed class Cmd
object Start : Cmd()
object Stop : Cmd()
fun execute(c: Cmd) {
// Statement form: no error if incomplete (avoid this style)
when (c) {
Start -> println("started")
Stop -> println("stopped")
}
}
fun main() { execute(Start); execute(Stop) }强制对语句进行完备性检查
请将 when 赋给一个值(或使用 .exhaustive 技巧),这样编译器就会强制检查所有情况。
sealed class Cmd
object Start : Cmd()
object Stop : Cmd()
fun execute(c: Cmd) {
val handled: Unit = when (c) { // expression context now
Start -> println("started")
Stop -> println("stopped")
}
}
fun main() { execute(Start) }多情况分支
使用逗号将多个情况分组,让它们共享同一个主体。
sealed class Event
class Click : Event()
class Tap : Event()
class Drag : Event()
fun isPointer(e: Event) = when (e) {
is Click, is Tap, is Drag -> true
}
fun main() { println(isPointer(Tap())) }嵌套密封类型
密封层次结构可以嵌套——即使在深层树结构上,完备性检查仍然有效。
sealed class Network {
sealed class Wifi : Network() {
object Open : Wifi()
data class Secured(val ssid: String) : Wifi()
}
object Cellular : Network()
}
fun describe(n: Network) = when (n) {
Network.Wifi.Open -> "open wifi"
is Network.Wifi.Secured -> "secured: ${n.ssid}"
Network.Cellular -> "cellular"
}
fun main() {
println(describe(Network.Wifi.Secured("home")))
println(describe(Network.Cellular))
}快速检查
将 when 与密封层次结构结合使用的主要优势是什么?
回顾
将密封类或密封接口与 when 配合使用,以实现编译时完备性检查。智能类型转换可以简化分支主体。请将其用作表达式(或赋值结果)来强制执行检查;使用逗号分组情况;嵌套密封类型以构建树形状态。
常见问题解答
「密封层次结构中的穷尽式 when」课时是免费的吗?
是的 — 「密封层次结构中的穷尽式 when」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。
「密封层次结构中的穷尽式 when」这节课中我会学到什么?
编写覆盖每个密封变体的完整 when 表达式。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Kotlin Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「密封层次结构中的穷尽式 when」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Kotlin Academy 课中编写并运行代码吗?
能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- sealed class 与 sealed interface:分别适用于何时
- 密封层次结构中的穷尽式 when
- 使用密封类建模界面状态
- 嵌套与组合密封层次结构