equals
オーバーライドがある場合、ケースクラスに対して通常生成される構造的同等性チェックは生成されないようです。ただし、いくつかの微妙な点に注意する必要があります。
IDベースの平等の概念を構造的平等にフォールバックすることを混合することは、微妙なバグにつながる可能性があると想像できるため、良い考えではないかもしれません。例えば:
x: A(1)
とy: A(1)
はまだ永続化されていないので、それらは等しい
- その後、それらは永続化され、それらは別個のオブジェクトであるため、永続化フレームワークはそれらを別個のエンティティとして永続化する可能性があります(Squerylはわかりませんが、問題ではないかもしれませんが、これは細い線です)
- 永続化した後、IDが異なるため、突然等しくなりません。
さらに悪いことに、x
とy
が同じIDにhashCode
永続化されると、永続化の前後で異なります(ソースは、永続化された場合、それがIDのhashCodeであることを示しています)。これは不変性を壊し、非常に悪い振る舞いにつながります(たとえばマップに配置された場合)。アサーションが失敗することを示すこの要点を参照してください。
したがって、構造的等式とIDベースの等式を暗黙的に混在させないでください。Hibernateのコンテキストで説明されているこれも参照してください。
型クラス
そのような理由で、メソッドベースの平等の概念に欠陥があることを他の人が指摘していることに注意する必要があります(2つのものが等しくなる方法は1つだけではありません)。したがって、等式を記述する型クラスを定義できます。
trait Eq[A] {
def equal(x: A, y: A): Boolean
}
クラスのその型クラスの(場合によっては複数の)インスタンスを定義します。
// structural equality
implicit object MyClassEqual extends Eq[MyClass] { ... }
// id based equality
def idEq[K, A <: KeyedEntity[K]]: Eq[A] = new Eq[A] {
def equal(x: A, y: A) = x.id == y.id
}
次に、物事がEq型クラスのメンバーであることを要求できます。
def useSomeObjects[A](a: A, b: A)(implicit aEq: Eq[A]) = {
... aEq.equal(a, b) ...
}
したがって、スコープに適切な型クラスをインポートするか、次のように型クラスインスタンスを直接渡すことで、使用する同等性の概念を決定できます。useSomeObjects(x, y)(idEq[Int, SomeClass])
Hashable
同様に、型クラスも必要になる場合があることに注意してください。
Eqインスタンスの自動生成
この状況は、scala.math.Ordering
Scalastdlibの型クラスと非常によく似ています。これは、優れたシェイプレスライブラリを使用してケースクラスの構造インスタンスを自動派生するOrdering
例です。
Eq
とについても同じことが簡単にできますHashable
。
Scalaz
scalazにはEqual
typeclassx === y
があり、の代わりに書くことができる素敵なpimpパターンがあることに注意してくださいeqInstance.equal(x, y)
。まだ型クラスがHashable
あるのかわかりません。