第37条:使用数据修饰符来表示一组数据

有时我们只需要传递一组数据,这就是我们使用 data class 的目的。这些是带有 data 修饰符的类,从我的经验来看,开发人员很快就会把它引入到他们的数据模型类中:

data class Player(
    val id: Int,
    val name: String,
    val points: Int
)

val player = Player(0, "Gecko", 9999)

当我们添加 data 修饰符时,它会生成一些有用的函数:

  • toString

  • equalshashCode

  • copy

  • componentNcomponent1component2等)

让我们根据数据类型依次讨论它们。

toString 显示类名和所有主构造函数属性的值及其名称。有助于日志的展示和调试:

print(player) // Player(id=0, name=Gecko, points=9999)

equls 检查是否所有的主构造函数属性都相等,并且 hashCode 与它是一致的(请看_第41条:遵守hashCode的合约_)。

copy 对于不可变数据类型非常有用,它创建了一个新的对象,其中每个主构造函数属性在默认情况下都具有相同的值,但可以使用具名参数更改它们:

我们无法看到 copy 方法的实现,因为它是在底层生成的,就像通过 data 修饰符生成的其它方法一样,如果我们能看到它,大概就是下面生成 Person 的样子:

注意,copy 方法对一个对象做了浅拷贝,但是当对象不可变的时候,这并不是问题 —— 对于不可变的对象,不需要深拷贝。

componentN 函数(component1component2 等等)允许基于其位置的解构,就像下面这个例子:

Kotlin 中的解构直接转化为使用 componentN 函数中的变量来定义,因此上面的代码将被编译成下面这段代码:

基于位置的解构有优点和缺点。最大的优点是我们可以随意命名变量,我们也可以分解我们想要的一切,只要它提供 componentN 函数。 ListMap.Entry 都能体现它 :

另一方面,它是危险的,当类中的元素顺序发生变化时,我们需要调整每一个解构。它也很容易因混乱的顺序而错误的分解:

我们需要小心地解构。使用和主构造函数中相同的属性的名称是很有用的,然后,不正确的顺序,IntelliJ / Android Studio 将会显示警告。甚至可以将警告升级为错误。

不要像下面的例子那样分解得到第一个值:

这可能会让读者感到困惑,特别是当你在 lambda 表达式中进行分解时:

这是有问题的,因为在一些语言中,lambda 表达式中包住参数的括号是可选或必需的。

优先使用 data class 替代元组(tunples)

data class 提供的功能比元组更多。更具体的说,Kotlin 元组只是可序列化的通用数据类型,并且有一个自定义的 toSring 方法:

为什么我只展示了 PairTriple? 这是因为它们是 Kotlin 最后剩下的元组类型。Kotlin 在 beta 版本就有无限元组了。我们可以通过括号和一组类型来定义类型,如: (Int, String, String, Long)。最后,我们所实现的行为与数据类相同,但可读性差很多。你能猜出这组类型代表什么吗? 它可以是任何东西,使用元组很诱人,但使用 data class 几乎总是更好!这就是为什么元组被删除,只留下 PairTriple,它们被保留下是出于一些在小范围内使用的意图,例如:

  • 当我们需要立即命名值时:

  • 表示一个事先没有被定义的组合 —— 通常在标准库中使用:

在其它情况下,我们更喜欢 data class。让我们来看一个例子,假设我们需要为一函数来将 fullname 解析为 name 和 surnname,可以将这个 name 和 surnname 表示为 Pair<String, String>:

问题是,当有人阅读它时,他并不清楚 Pair<String, String> 里面的每个类型分别表示的是什么。更重要的是,这些值的顺序并不清楚,有人认为可能 surnname 会在前面:

为了使引用更加安全、函数更加易读,我们应该使用数据类型:

它的成本几乎为0,并且显著改善了功能:

  • 函数的返回类型是明确的

  • 返回类型更短,更容易传递

  • 如果用户解构的变量名不同,则会显示一个警告

如果不希望这个类在更大范围内使用时,可以限制其可见性,如果你只需要在单个文件或类中用某些本地函数处理使用它,它甚至可以是私有的。我们更值得去使用 data class 而不是元组。 Kotlin 的类成本很低,请不要害怕使用它们。

Last updated