Kotlin——数据类和密封类

时间:2022-07-15 05:37:16

数据类

有些类只是用来持有数据的。在这样的类中,一些标准的函数通常是从数据中推导出来的。在Kotlin中,这些类成为数据类并且以data作为标记:

data class User(val name: String, val age: Int)

编译器自动从主构造器中的属性导入下面这些成员函数:
- equals()/hashCode()
- toString()(形式为User(name=John,age=42))
- componentN()函数对应着声明的属性顺序
- copy()函数

如果上面的函数显式地定义了或者继承自父类,那么将不会自动创建。
为了确保生成的代码的一致性和有意义的行为,数据类必须满足以下需求:
- 主构造器至少有一个参数
- 主构造器的参数必须以valvar标记
- 数据类不可以是abstract、open、sealed或者inner
- (在1.1之前)数据类只能实现接口

从1.1开始,数据类可以继承自其它类。
在JVM上,如果生成的类需要有一个没有参数的构造器,那么所有属性必须指定默认值。比如:

data class User(val name: String = "", val age: Int = 0)

拷贝

经常有这样一种场景,我们需要从复制某个对象,然后修改某些属性,并且保持原有对象的不变。这就是copy()函数出现的原因。对于上面的User类,它的实现如下:

fun copy(name: String = this.name, age: Int = this.age) = User(name, age)

使用的话可以如下:

 val jack = user.copy(name = "jack", age = 26)

数据类和解析声明

为数据类生成的 Component 函数 使它们可在解构声明中使用:

val user = User("wangli", 25)
val (name, age) = user
println("$name,$age years of age") //输出wangli,25 years of age

标准数据类

标准库提供了PairTriple。在大多数情况下,命名数据类是一个更好的设计选择,因为他们通过为属性提供更有意义的命名来增强可读性。

密封类

密封类用于表示受限制的类层次结构,当一个值只能在一个集合中取值时,而不能取其他值时。在某种意义上,这是枚举类的扩展:枚举类型的值集合
也是受限的,但每个枚举常量只存在一个实例,而密封类
的一个子类可以有可包含状态的多个实例。
为了声明密封类,需要在类名之前使用sealed作为修饰符。一个密封类是可以有子类的,但是所有的子类必须和父类生命在同一个文件中。

sealed class Expr

data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()

需要注意的是,密封类的非直接继承的子类可以声明在其他文件中。
密封类的主要好处在于使用when表达式。如果能够
验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。

fun eval(expr: Expr): Double = when (expr) {

is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN

//else被忽略,因为覆盖了所有可能性

}

说明

关于代码请参考我的Github地址