假设我想为整数列表声明一个简单的代数数据类型:
sealed class IntList
data class Cons(val head: Int, val tail: IntList): IntList()
data class Nil() : IntList()
但是,最后一个声明会导致错误
数据类必须至少有一个主构造函数参数
-
为什么会出现此限制?查看文档,似乎没有很好的技术理由要求数据类构造函数是非空的 .
-
是否可以表示无需构造函数而无需编写大量的样板代码?如果我将最后一个声明更改为类似的
sealed class Nil() : IntList()
然后我失去了 hashCode()
和 equals()
的免费实现,它们是 data class
声明免费提供的 .
EDIT
Alex Filatov给出了一个很好的简短解决方案 . 显然,你永远不需要多个 Nil
的实例,所以我们可以只定义一个单例对象
object Nil : IntList()
但是,如果我们的列表由类型参数参数化,我们会怎么做?也就是说,现在我们定义的前两行是
sealed class List<A>
data class Cons<A>(val head: A, val tail: List<A>): List<A>()
我们不能声明从 List<A>
派生的任何 A
的多态单例 Nil
对象,因为我们必须在声明时为 A
提供具体类型 . 解决方案(取自this post)是将 A
声明为协变类型参数,并将 Nil
声明为 List<Nothing>
的子类型,如下所示:
sealed class List<out A>
data class Cons<A>(val head: A, val tail: List<A>): List<A>()
object Nil : List<Nothing>()
这允许我们写
val xs: List<Int> = Cons(1, Cons(2, Nil))
val ys: List<Char> = Cons('a', Cons('b', Nil))
3 回答
你将不得不创建一个通常的类
并自己实施
hashCode()
和equals()
.没有字段的数据类没有任何意义,因为它的工作是表示数据 .
或者:您可以使用一个对象类(如Alex Filatov所述),它是一个单实例类 . 因为,每个单独的
Nil
实例都不需要状态,所以它们可以共享一个 .如果您真的想要源代码的一致性,可以使用默认值来实现最小的数据类型 .
要么
因为
data class
没有数据没有意义 . 使用object
作为单身人士: