0Pricing
Kotlin Academy · 课时

密封层次结构中的穷尽式 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 反馈 — 无需本地设置。

此课程中的所有课时

  1. sealed class 与 sealed interface:分别适用于何时
  2. 密封层次结构中的穷尽式 when
  3. 使用密封类建模界面状态
  4. 嵌套与组合密封层次结构
← 返回 Kotlin Academy