【问题标题】:Prevent Mixin overriding equals from breaking case class equality防止 Mixin 覆盖 equals 破坏 case 类相等
【发布时间】:2012-09-08 05:24:38
【问题描述】:

Squeryl 定义了一个 trait KeyedEntity 覆盖 equals,检查 if 中的几个条件并在最后调用 super.equals。由于superObject,所以它总是会失败。

考虑:

trait T { override def equals(z: Any):Boolean = super.equals(z)} }

case class A(a: Int) extends T

val a = A(1); val b = A(1)

a==b // false

因此,如果你声明

case class Record(id: Long, name: String ...) extends KeyedEntity[Long] { ... }

-- 你创建了几个 Record 实例但不持久化它们,它们的比较会中断。我通过为同一个类同时实现SalatSqueryl 后端发现了这一点,然后所有Salat 测试都失败了,因为来自KeyedEntityisPersisted 是错误的。

如果KeyedEntity 混合到一个案例类中,是否有一种设计可以保持案例类的平等?我尝试将案例类类型为 P 的自键入和参数化 BetterKeyedEntity[K,P] { self: P => ... },但它会导致 equals 中的无限递归。

就目前的情况而言,superObject,因此 KeyedEntity 中覆盖的 equals 的最终分支将始终返回 false。

【问题讨论】:

    标签: scala squeryl


    【解决方案1】:

    如果有equals 覆盖,通常为案例类生成的结构相等检查似乎不会生成。但是,必须注意一些细微之处。

    将基于 id 的相等概念混合到结构相等可能不是一个好主意,因为我可以想象它可能会导致细微的错误。例如:

    • x: A(1)y: A(1) 还没有持久化,所以它们是相等的
    • 然后它们会被持久化,并且由于它们是独立的对象,持久性框架可能会将它们作为独立的实体持久化(我不知道 Squeryl,那里可能不是问题,但这是一条细线)
    • 坚持后突然不相等,因为id不同。

    更糟糕的是,如果 xy 被持久化到相同的 id,hashCode 在持久化前后会有所不同(the source 表明如果持久化它是 id 的 hashCode)。这破坏了不变性,并会导致非常糟糕的行为(例如,当放在地图中时)。见this gist in which I demonstrate the assert failing

    所以不要隐含地混合结构和基于id的相等性。另请参阅context of Hibernate.

    中的解释

    类型类

    必须注意,其他人指出(需要参考)基于方法的相等的概念是有缺陷的,因为这些原因(两个事物相等的方法不止一种)。因此,您可以定义一个描述 Equality 的类型类:

    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 标准库的 scala.math.Ordering 类型类非常相似。这是一个使用优秀的shapeless 库的auto-deriving structural Ordering instances for case classes 示例。

    EqHashable 也很容易做到这一点。

    Scalaz

    请注意scalaz has Equal typeclass,带有漂亮的皮条客模式,您可以使用它编写x === y 而不是eqInstance.equal(x, y)。我还不知道它有 Hashable 类型类。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多