密封类:用来定义受限的类继承结构。
在when表达式中处理所有可能的子类,我们必须提供一个else分支来处理没有任何其他分支能匹配的情况:
interface Expr
class Num(val value:Int):Expr
class Sum(val left:Expr,val right:Expr):Expr
fun eval(e:Expr):Int =
when(e){
is Num -> e.value
is Sum -> eval(e.left) + eval(e.right)
//必须使用else
else -> 0
}
当使用when结构来执行表达式的时候,Kotli编译器会强制检查默认选项。总是不得不添加一个默认分支很不方便。更重要的是,如果你添加了一个新的子类,编译器并不能发现有地方改变了。如果你忘记添加一个新分支,就会选择默认的选项,这有可能导致潜在的bug。sealed密封类就是一种解决该问题的方案。
为父类添加一个sealed修饰符,对可能创建的子类做出严格的限制,所有的直接子类必须嵌套在父类中。
sealed class Expr{
class Num(val value:Int):Expr()
class Sum(val left:Expr,val right:Expr):Expr()
data class Data(val value: Int):Expr()
}
fun eval(e:Expr):Int =
when(e){
is Expr.Num -> e.value
is Expr.Sum -> eval(e.left) + eval(e.right)
is Expr.Data -> e.value
}
如果在when表达式中处理所有的sealed子类,你就不再需要提供默认分支。注意:sealed修饰符隐含的这个类是一个open类,你不再需要显示地添加open修饰符。
好处:当你在when中使用sealed类并且添加一个新的子类的时候,有返回值的when表达式会导致编译失败,它会告诉你哪里的代码必须要修改。
注意:
在Kotlin1.0中,sealed要求所有的子类必须是嵌套的,并且子类不能创建为data类。在Kotlin1.1解除了这些限制并允许在同一个文件的任何位置定义sealed类的子类。