假设我想为整数列表声明一个简单的代数数据类型:
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
声明。
修改
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))
答案 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()