2013-10-04 12 views
12

スカラには、実行時に2つのオブジェクトを構造的に比較する関数がありますか?私はむしろフィールドの数のために等価関数を手動で作成する必要はありません。これは単体テストのためであり、パフォーマンスは問題ではありません。私はフィールドを見渡し、値を比較するようなものが必要です。Scalaの実行時に構造化された等価物

背景:私は、等価をオーバーライドして構造的等価(squeryl KeyedEntity、related:Prevent Mixin overriding equals from breaking case class equality)を生成しない特性から継承したケースクラスを持っています。 。これはユニットテストのためで、両方のインスタンスが永続化されません。

+2

ケースクラスのオブジェクトでは、ケースクラス値のみに興味がある場合は、 'productIterator.toList'を使用できます。 – pedrofurla

+0

productIterator.toListが機能しませんでした。それはインスタンスをリストに入れるだけです。 – ttt

+0

両方のオブジェクトを反映し、フィールドと値を比較します。 – Ashalynd

答えて

1

私はすべてのフィールドを繰り返し処理するこのソリューションを考え出し、プライベートフィールドの場合は対応するメソッドをスカラーで検索します。実際、ケースクラスには、同じ名前のメソッドでアクセスできるプライベートメンバーがあります。

implicit class ReallyEqual[T](a: T) { 
    import java.lang.reflect.Modifier._ 
    def ==:==[U](b: U): Boolean = { 
    val fieldsA = a.getClass.getDeclaredFields 
    val methodsA = a.getClass.getDeclaredMethods 
    val mapA = (methodsA.toList map (z => (z.getName(), z))).toMap 
    val fieldsB = b.getClass.getDeclaredFields 
    val methodsB = b.getClass.getDeclaredMethods 
    val mapB = (methodsB.toList map (z => (z.getName(), z))).toMap 
    fieldsA.length == fieldsB.length && 
    (true /: (fieldsA zip fieldsB)){ case (res, (aa, bb)) => 
     if(((aa.getModifiers & STATIC) != 0) || ((bb.getModifiers & STATIC) != 0)) { res // ignore 
     } else if(((aa.getModifiers & (PRIVATE | PROTECTED)) == 0) && ((bb.getModifiers & (PRIVATE | PROTECTED)) == 0)) { 
     res && aa == bb && aa.get(a) ==:== bb.get(b) 
     } else if((mapA contains aa.getName) && (mapB contains bb.getName)) { 
     res && mapA(aa.getName).invoke(a) == mapB(aa.getName).invoke(b) 
     } else res 
    } 
    } 
} 

trait EqualBad { 
    override def equals(other: Any) = false 
} 

case class MyCaseClass(x: Int, y: List[Int]) extends EqualBad 

MyCaseClass(1, List(1, 2)) ==:== MyCaseClass(1, List(1, 2)) // true 
MyCaseClass(1, List(1, 2)) ==:== MyCaseClass(1, List(2, 2)) // false 
MyCaseClass(1, List(1, 2)) ==:== MyCaseClass(2, List(1, 2)) // false 
MyCaseClass(1, List(1, 2)) == MyCaseClass(1, List(1, 2)) // false 

あなたも、この方法では、最後の==を変更することで、それがより再帰的にすることができReallyEqualに==:==

慎重に:intは持っていないので、これは、整数のために動作しません。任意のフィールドまたはメソッド。 例:1 ==:== 2はtrueを返します。

1

AFAIKスカラ標準ライブラリには、このような関数は含まれていません。しかし、あなたには2つの選択肢があります。

  1. あなたはパフォーマンスが問題にならない場合は2つの与えられた値
  2. 使用するJavaリフレクションの平等を比較する方法を生成するマクロを書きます。この回答を見るIs there a Java reflection utility to do a deep comparison of two objects?
+1

このようなマクロを書くと、この回答が賞金を獲得する可能性があります。 –

+4

3.スカラ反射を使用します。 –

関連する問題