我如何定义将由不可变集合比较方法使用的自定义相等操作

我有一个不可变的类Set [MyClass] Set,我想使用Set方法intersect和diff,但我希望他们使用我的自定义equals方法testing相等性,而不是默认的对象相等性testing

我已经尝试覆盖==运算符,但它没有被使用。

提前致谢。

编辑:

交集方法是GenSetLike的具体值成员

规格: http : //www.scala-lang.org/api/current/scala/collection/GenSetLike.html src: https : //lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src //library/scala/collection/GenSetLike.scala#L1

def intersect(that: GenSet[A]): Repr = this filter that 

所以交叉口是使用过滤方法完成的。

又一个编辑:

filter在TraversableLike中定义

规格: http : //www.scala-lang.org/api/current/scala/collection/TraversableLike.html

src: https : //lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src//library/scala/collection/TraversableLike.scala#L1

 def filter(p: A => Boolean): Repr = { val b = newBuilder for (x <- this) if (p(x)) b += x b.result } 

我不清楚什么是没有谓词的情况下使用它,p。 这不是一个隐含的参数。

只有在没有定义它们的情况下,才会自动在case类中提供equals和hashCode。

 case class MyClass(val name: String) { override def equals(o: Any) = o match { case that: MyClass => that.name.equalsIgnoreCase(this.name) case _ => false } override def hashCode = name.toUpperCase.hashCode } Set(MyClass("xx"), MyClass("XY"), MyClass("xX")) res1: scala.collection.immutable.Set[MyClass] = Set(MyClass(xx), MyClass(XY)) 

如果你想要的是引用的平等,还是写equals和hashCode,以防止自动生成,并从AnyRef调用版本

  override def equals(o: Any) = super.equals(o) override def hashCode = super.hashCode 

接着就,随即:

 Set(MyClass("x"), MyClass("x")) res2: scala.collection.immutable.Set[MyClass] = Set(MyClass(x), MyClass(x)) 

你不能覆盖来自AnyRef的==(o: Any) ,它是封闭的,总是调用equals。 如果你尝试定义一个新的(重载的) ==(m: MyClass) ,那不是Set调用的那个,所以在这里是没用的,而且一般来说相当危险。

至于filter的调用,它的工作原因是Set[A]是一个Function[A, Boolean] 。 是的,使用equals ,你会看到函数实现( apply )是contains一个同义词,并且Set use == in的大部分实现都包含在其中( SortedSet使用Ordering )。 ==电话equals


注意:我的第一个equals的实现是快速和肮脏的,如果MyClass被子类化,可能会很糟糕。 如果是这样,至less应该检查types是否相等( this.getClass == that.getClass )或者更好的定义一个canEqual方法(您可以阅读Daniel Sobral的博客 )

你也需要覆盖.hashCode 。 当您覆盖.equals ,几乎总是这样,因为.hashCode经常用作对.equals更便宜的.equals ; 任何两个相等的对象必须具有相同的散列码。 我猜你正在使用的对象的默认hashCode不尊重这个属性相对于你自定义的相等性,并且Set实现正在做基于哈希代码的假设(所以从来没有甚至调用你的相等操作)。

查看Scala文档Any.equalsAny.hashCode : http : //www.scala-lang.org/api/rc/scala/Any.html

这个答案显示了一个自定义的可变集合与用户定义的平等 。 通过用Vectorreplace内部存储并在每次操作时返回自身的修改副本,可以使其不可变

“直接覆盖==是不可能的,因为它被定义为类Any中的最后一个方法。也就是说,Scala将==视为在类Any中定义如下:

  final def == (that: Any): Boolean = if (null eq this) {null eq that} else {this equals that} 

“从编程斯卡拉,第二版