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

时间:2017-09-11 09:38:49

标签: 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声明。

  3. 修改

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

    object Nil : IntList()
    

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

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

    我们无法为任何Nil声明从List<A>派生的多态单一A对象,因为我们必须在声明时为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 个答案:

答案 0 :(得分:12)

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

object Nil : IntList()

答案 1 :(得分:0)

您必须创建一个通常的类

class Nil : IntList()

并自己实施hashCode()equals()

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

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

答案 2 :(得分:-2)

如果您真的想要源代码的一致性,可以使用默认值来实现最小的数据类型。

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

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