封閉類用于反應被限制了的類層次結構:一個值的類型只能是有限集合中的一種,而不能是集合外的其他類型。它們在某種意義上是枚舉類的擴展:枚舉類型的值的集合也被限制,每個枚舉常量僅作為單個實例存在;然而封閉類的子類可以有多個實例,且這些實例仍然可以持有狀態。
要想聲明一個封閉類,需要在類名前添加sealed
修飾符。一個封閉類可以有子類,但是這些子類必須在和封閉類同一個文件中聲明。(在Kotlin1.1之前,規則更苛刻:子類必須嵌套在封閉類的內部)。
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
fun eval(expr: Expr): Double = when (expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
}
(上面這段代碼使用了Kotlin1.1的一個新特性:數據類可以繼承其他類,也包括封閉類。)
注意:繼承(直接繼承)封閉類的子類的類,可以放置在其他任意地方,不必非要放在同一個文件中。
使用密封類的關鍵好處是在使用when
表達式時使用它們。如果可以保證該語句涵蓋了所有情況,則不需要在語句中添加一個else子句。
fun eval(expr: Expr): Double = when(expr) {
is Expr.Const -> expr.number
is Expr.Sum -> eval(expr.e1) + eval(expr.e2)
Expr.NotANumber -> Double.NaN
// the `else` clause is not required because we've covered all the cases
}