【发布时间】:2017-09-11 09:38:49
【问题描述】:
假设我想为整数列表声明一个简单的代数数据类型:
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>()
我们不能为任何A 声明派生自List<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))
【问题讨论】:
-
Related: stackoverflow.com/questions/37873995/… 不过好像不适合你的情况。
-
另外,“请注意,未在主构造函数中声明的属性不参与相等性检查和哈希码计算。”
-
@UlrikRasmussen 如果类不应包含任何字段,为什么需要
hashCode()和equals()? -
如果我想比较两个列表。但这只是在存在 Nil 的不同实例时才会出现的问题。通过将 Nil 表示为单例,这些方法的默认实现就足够了
-
@UlrikRasmussen 请发布您的编辑作为答案! :) 答案不应该出现在问题中
标签: kotlin