Scala中运行时的结构化相等

Scala中运行时的结构化相等,scala,Scala,scala中是否有一些函数可以在运行时从结构上比较两个对象?由于字段的数量,我不想手动创建equals函数。这是一个单元测试,所以性能不是问题。我只需要一些能反射地查看字段并比较值的东西 背景:我有一个case类,它是从一个覆盖equals的特征扩展而来的,因此不会生成结构上的equals(squeryl-KeyedEntity,related:),我现在无法改变这一点。这是用于单元测试的,因此这两个实例都不会持久化。AFAIK Scala标准库不包含这样的函数。但你有两个选择 编写一个宏,该宏

scala中是否有一些函数可以在运行时从结构上比较两个对象?由于字段的数量,我不想手动创建equals函数。这是一个单元测试,所以性能不是问题。我只需要一些能反射地查看字段并比较值的东西


背景:我有一个case类,它是从一个覆盖equals的特征扩展而来的,因此不会生成结构上的equals(squeryl-KeyedEntity,related:),我现在无法改变这一点。这是用于单元测试的,因此这两个实例都不会持久化。

AFAIK Scala标准库不包含这样的函数。但你有两个选择

  • 编写一个宏,该宏生成一个方法来比较两个给定值的相等性
  • 如果性能不重要,请使用Java反射。看看这个答案:

  • 我提出了这个解决方案,它迭代所有字段,对于私有字段,在scala中找到相应的方法。事实上,case类具有通过同名方法访问的私有成员

    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没有任何字段或方法。
    Ex:1==:==2将返回true。

    在案例类的对象中,如果您只对案例类值感兴趣,则可以使用
    productIterator.toList
    。productIterator.toList不起作用。这只是将实例放入一个列表中。反映两个对象并比较它们的字段和值。如果您编写这样一个宏,这个答案可能会赢得赏金。3。使用Scala反射。