69

何か他のものを探しているときに、単なる偶然から、ケースクラスの継承がいかに悪魔的であるかについてのコメントをいくつか見つけました。、惨めな人と王様、エルフと魔法使いと呼ばれるものがありProductN、ケースクラスの継承により、ある種の非常に望ましいプロパティがどのように失われるかがありました。では、ケース クラスの継承の何が問題になっているのでしょうか。

4

2 に答える 2

115

一言:平等

caseequalsクラスには、およびの提供された実装が付属していhashCodeます。として知られる同値関係equalsは、次のように機能します (つまり、次のプロパティが必要です)。

  1. すべてのためにx; x equals xですtrue(再帰)
  2. xyz; _ if x equals yand y equals zthen x equals z(他動詞)
  3. のためxに、y; if x equals ythen 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ません)。ColoredPointcolor

これにより、ケース クラス階層の等価性をどのように実装できるかが理解できます。

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 に答える