在Kotlin中,如何用零构造函数参数声明一个数据类?

假设我想为整数列表声明一个简单的代数数据类型:

sealed class IntList data class Cons(val head: Int, val tail: IntList): IntList() data class Nil() : IntList() 

但是,最后的声明会导致错误

数据类必须至少有一个主构造函数参数

  1. 为什么这个限制存在? 查看文档,似乎没有好的技术理由要求数据类构造函数是非空的。
  2. 是否有可能表达无用的构造函数,而不必写大量的样板代码? 如果我把最后一个声明改成类似的东西

     sealed class Nil() : IntList() 

    那么我会失去hashCode()equals()这些免费的data class声明的免费实现。

编辑

Alex Filatov在下面给出了一个很好的简短解决方案。 显然,你永远不需要多于一个的Nil实例,所以我们可以定义一个单例对象

 object Nil : IntList() 

但是,如果我们的列表是通过类型参数进行参数化的,我们该怎么办? 也就是说,现在我们定义的前两行是

 sealed class List<A> data class Cons<A>(val head: A, val tail: List<A>): List<A>() 

我们不能为任何A声明一个从List<A>派生的多态Singleton Nil对象,因为我们必须在声明时为A提供一个具体的类型。 解决方案(取自此帖子 )是将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)) 

因为没有数据的data class没有意义。 使用object的单身人士:

 object Nil : IntList() 

你将不得不创建一个平常的课程

 class Nil : IntList() 

并自己实现hashCode()equals()

没有字段的数据类没有任何意义,因为它的工作是表示数据。


或者:您可以使用一个对象类(如Alex Filatov所说),这是一个单一的实例类。 因为你不需要每个Nil实例的状态,他们可以共享一个。

如果你真的想要你的源代码统一,你可以使用默认值的最小数据类型。

 data class Nil(val _u: Byte = 0) : IntList() 

要么

 data class Nil(val _u: Nothing? = null) : IntList()