在寻找其他东西时,完全出于巧合,我偶然发现了一些关于恶魔案例类继承如何的评论。有一个东西叫做ProductN
,坏蛋和国王,精灵和巫师,以及一些非常理想的属性是如何随着案例类继承而丢失的。那么案例类继承有什么问题呢?
问问题
13864 次
2 回答
115
一个字:平等
case
类提供了equals
和的实现hashCode
。等价关系,称为这样的equals
工作(即必须具有以下属性):
- 对于所有人
x
;x equals x
是true
(反身的) - 对于
x
,y
,z
; 如果x equals y
然后(传递y equals z
)x equals z
- 对于
x
,y
; 如果x equals y
那么y equals x
(对称)
只要您允许继承层次结构中的相等性,您就可以打破 2 和 3。以下示例简单地证明了这一点:
case class Point(x: Int, y: Int)
case class ColoredPoint(x: Int, y: Int, c: Color) extends Point(x, y)
然后我们有:
Point(0, 0) equals ColoredPoint(0, 0, RED)
但不是
ColoredPoint(0, 0, RED) equals Point(0, 0)
你可能会争辩说所有的类层次结构都可能有这个问题,这是真的。但是从开发人员的角度来看,案例类的存在专门用于简化相等性(以及其他原因),因此让它们以非直觉的方式表现将是对自己目标的定义!
还有其他原因;尤其是copy
没有按预期工作以及与模式匹配器交互的事实。
于 2012-06-22T15:12:44.207 回答
-2
这并不完全正确。这比谎言更糟糕。
正如aepurniet所提到的,在任何情况下,限制定义区域的类后继者都必须重新定义相等性,因为模式匹配必须与相等性完全相同(如果尝试匹配Point
,ColoredPoint
那么它将不匹配,因为color
它不存在)。
这有助于理解如何实现案例类层次结构的相等性。
case class Point(x: Int, y: Int)
case class ColoredPoint(x: Int, y: Int, c: Color) extends Point(x, y)
Point(0, 0) equals ColoredPoint(0, 0, RED) // false
Point(0, 0) equals ColoredPoint(0, 0, null) // true
ColoredPoint(0, 0, RED) equals Point(0, 0) // false
ColoredPoint(0, 0, null) equals Point(0, 0) // true
最终有可能满足相等关系的要求,即使是案例类的后继者(不覆盖相等性)。
case class ColoredPoint(x: Int, y: Int, c: String)
class RedPoint(x: Int, y: Int) extends ColoredPoint(x, y, "red")
class GreenPoint(x: Int, y: Int) extends ColoredPoint(x, y, "green")
val colored = ColoredPoint(0, 0, "red")
val red1 = new RedPoint(0, 0)
val red2 = new RedPoint(0, 0)
val green = new GreenPoint(0, 0)
red1 equals colored // true
red2 equals colored // true
red1 equals red2 // true
colored equals green // false
red1 equals green // false
red2 equals green // false
def foo(p: GreenPoint) = ???
于 2016-04-06T16:30:00.793 回答