加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 防止Mixin重写equals以打破case类的相等性

发布时间:2020-12-16 08:47:22 所属栏目:安全 来源:网络整理
导读: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 Tval a = A(1); va
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)尚未持久化,因此它们是相等的
>然后它们会被持久化,并且因为它们是独立的对象,持久性框架可能会将它们作为单独的实体保留(我不知道Squeryl,也许不是问题,但这是一条很细的行走)
>坚持之后,由于身份不同,他们突然不相等.

更糟糕的是,如果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 Ordering instances for case classes使用优秀shapeless库的示例.

Eq和Hashable也很容易做到这一点.

Scalaz

注意scalaz has Equal typeclass,有很好的皮条客模式,你可以用它来写x === y而不是eqInstance.equal(x,y).我不知道它有Hashable类型类.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读