大家好,我是William李梓峰,欢迎加入我的Kotlin学习之旅。
今天是我学习 Kotlin 的第十四天,内容是 Sealed Classes - 密封类。
官方文档:
Sealed Classes - 密封类
Sealed classes are used for representing restricted class hierarchies, when a value can have one of the types from a limited set, but cannot have any other type.
密封类是用于表示等级严谨的类,当一个值可以从一个有限集中拥有一个类型而不能有其他类型,密封类就能发挥其作用。(写的有点飘,靠谱的理解在下面~)
They are, in a sense, an extension of enum classes: the set of values for an enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed class can have multiple instances which can contain state.
密封类,实际上是一个枚举类的扩展形式:集合的枚举类型是严格要求的,但是每个枚举常量仅存在一个单例,而密封类的子类可以包含状态。
To declare a sealed class, you put the sealed
modifier before the name of the class. A sealed class can have subclasses, but all of them must be declared in the same file as the sealed class itself. (Before Kotlin 1.1, the rules were even more strict: classes had to be nested inside the declaration of the sealed class).
为了声明一个密封类,你可以在类的前面写 sealed 修饰符。一个密封父类可以拥有密封子类,但是所有密封子类都必须声明在同一个文件里面,该文件就是密封父类声明所在的地方。(在 Kotlin 1.1 之前,这个规则更加苛刻:子类必须在父类内部声明,多恶心)
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
(The example above uses one additional new feature of Kotlin 1.1: the possibility for data classes to extend other classes, including sealed classes.)
(上面的例子使用了 Kotlin 1.1的一个新特性:数据类可以继承其他类,包括密封类)
Note that classes which extend subclasses of a sealed class (indirect inheritors) can be placed anywhere, not necessarily in the same file.
要知道的是,那些继承了密封类的子类(间接继承)可以放在任何地方,不一定是在同一个文件内部。(例如数据类继承了某个密封类,而这个数据类可以放置任何一个地方,不一定要在密封类所在的文件下)
The key benefit of using sealed classes comes into play when you use them in a when
expression. If it's possible to verify that the statement covers all cases, you don't need to add an else
clause to the statement.
使用密封类最关键的好处就是在 when 表达式 那里的应用。如果判断语句覆盖了所有的密封类实例,则你不再需要额外写 else 语句。(好像方便了一点,不过说真的,密封类相当于枚举类,唯一不同就是普通类可以继承密封类,而枚举类则不行。)
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
// the `else` clause is not required because we've covered all the cases
}
这里官方文档没有给出丰富的密封类的使用例子,可能好戏在后头,例如 Kotlin Koan。