案例类继承的* so *错误是什么?

时间:2012-06-22 15:06:59

标签: scala inheritance case-class

在寻找别的东西时,我非常巧合地偶然发现了一些关于恶魔案件类继承的评论。有一个名为ProductN的东西,可怜的和国王,精灵和巫师,以及如何通过案例类继承丢失某种非常理想的属性。那么case类继承有什么问题呢?

2 个答案:

答案 0 :(得分:108)

一个词:平等

case个类附带了equalshashCode的提供实现。等价关系,称为equals,就像这样(即必须具有以下属性):

  1. 适用于所有x; x equals xtrue(反身)
  2. xyz;如果x equals yy equals zx equals z(及时)
  3. xy;如果x equals y然后y equals x(对称)
  4. 只要在继承层次结构中允许相等就可以中断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 did not work as expectedinteraction with the pattern matcher

答案 1 :(得分:-2)

这不完全正确。这比谎言更糟糕。

正如aepurniet所提到的,在任何情况下,包含定义区域的类继承者必须重新定义相等性,因为模式匹配必须完全相同(如果尝试将PointColoredPoint匹配,那么它不会匹配,因为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) = ???