scala – 防止Mixin重写equals以打破case类的相等性
Squeryl定义了一个特征KeyedEntity,它覆盖了equals,检查if中的几个条件,最后调用super.equals.由于super是Object,它总是会失败.
考虑: 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实例但不保留它们,它们的比较将会中断.我通过为同一个类实现Salat和Squeryl后端找到了这个,然后所有Salat测试失败,因为来自KeyedEntity的isPersisted是错误的. 是否存在KeyedEntity如果混合到案例类中将保持案例类相等的设计?我尝试了自我键入和参数化BetterKeyedEntity [K,P] {self:P => …}将case类类型作为P,但它会导致equals中的无限递归. 就像现在的情况一样,super是Object,因此KeyedEntity中被覆盖的equals的最终分支将始终返回false. 解决方法
如果存在等于覆盖,则通常不会生成通常为案例类生成的结构相等性检查.然而,必须注意一些细微之处.
将基于身份的平等概念混淆回到结构平等可能不是一个好主意,因为我可以想象它可能会导致微妙的错误.例如: > x:A(1)和y:A(1)尚未持久化,因此它们是相等的 更糟糕的是,如果x和y持久化到相同的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 stdlib的scala.math.Ordering类型类.以下是auto-deriving structural Eq和Hashable也很容易做到这一点. Scalaz 注意scalaz has (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |