虽然寻找别的东西,相当出纯粹的巧合,我偶然发现有关类继承如何毒辣的情况是几点意见。 有这个东西叫做ProductN
,坏蛋和国王,精灵和巫师,以及如何某种非常理想的财产损失与case类继承。 那么,什么是错用的情况下类继承?
Answer 1:
一个字: 平等
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)
你可能会认为,所有的类层次结构可能有这个问题,这是真的。 但是case类具体存在简化从开发人员的角度平等(除其他原因外),所以有他们的行为非直观的将是自己的目标定义!
还有其他一些原因,以及; 值得注意的是事实, copy
没有按预期工作 ,并与模式匹配的交互 。
Answer 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类的继任者平等关系的要求(无平等的覆盖)。
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) = ???
文章来源: What is *so* wrong with case class inheritance?