most form ​​reference​

数据类

我们经常创建一个类,只能持有数据。在这样一个类中,一些标准功能通常是从数据中机械推导出来的。在Kotlin中,这被称为数据类,标记为data:

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

编译器自动从主构造函数中声明的所有属性生成以下成员:

  • equals() / hashCode()
  • toString() 的形式 “User(name=Jackie, age=24)”
  • ​componentN()函数​​对应于属性的声明顺序
  • copy()函数(见下文)

如果这些函数中的任何一个在类体中被明确定义,或者从基类型继承,那么它将不被生成。
为了确保生成的代码的一致性和有意义的行为,数据类必须满足一下要求:

  • 主要构造函数需要至少有一个参数
  • 所有主要构造函数参数需要标记为val或var
  • 数据类不能抽象,开放,密封或内部
  • (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 jackie = User(name = "Jackie", age = 1)
val olderJackie = jackie.copy(age = 2)

数据类的解构声明

为数据类生成的组件函数可用于​​解构声明​​:

val jane = User("Jane", 35) 
val (name, age) = jane
println("$name, $age years of age") // prints "Jane, 35 years of age"

标准数据类

标准库提供Pair和Triple。在大多数情况下,命名数据类是更好的设计选择,因为他们通过为属性提供有意义的名称使代码更易读。

密封类

密封类用于表示受限类层次结构,当值可以有一个有限集合的类型,但不能有其他类型。它们在某种意义上是枚举类的扩展:枚举类型的值集合也受到限制,但每个枚举常量仅作为单个实例存在,而密封类的子类可以包含多个可包含的实例。
要声明一个密封类,将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()

(上面的例子使用了Kotlin1.1的一个额外的新功能:数据类扩展其他类的可能性,包括密封类)。
请注意,扩展密封类子类的类可以放置在任何位置,而不一定在同一个文件中。
使用密封类的关键好处是在​​​when表达式​​使用它们时发挥作用。如果可以验证该语句涵盖所有情况,则不需要else在语句中添加字句。但是,仅当您使用when表达式(使用结果)而不是作为语句时,这才有效。

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
}