繁体   English   中英

Scala中运行时的结构化等于

[英]Structured equals at runtime in Scala

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

背景:我有一个案例类,它从一个覆盖等于的特征延伸,因此不会生成结构等于(squeryl KeyedEntity,相关: 防止Mixin重写等于破坏案例类相等 ),我不能够现在改变它。 这是针对单元测试的,因此两个实例都不会保留。

AFAIK Scala标准库不包含这样的功能。 但是你有两种选择。

  1. 您编写一个宏,它生成一个比较两个给定值的相等性的方法
  2. 如果性能无关紧要,请使用Java反射。 看到这个答案: 是否有一个Java反射实用程序来对两个对象进行深度比较?

我想出了这个迭代遍历所有字段的解决方案,对于私有字段,在scala中找到相应的方法。 实际上,案例类的私有成员可以通过相同名称的方法访问。

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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM