封闭类用于反应被限制了的类层次结构:一个值的类型只能是有限集合中的一种,而不能是集合外的其他类型。它们在某种意义上是枚举类的扩展:枚举类型的值的集合也被限制,每个枚举常量仅作为单个实例存在;然而封闭类的子类可以有多个实例,且这些实例仍然可以持有状态。
要想声明一个封闭类,需要在类名前添加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
}