我如何定义将由不可变集合比较方法使用的自定义相等操作
我有一个不可变的类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.equals
和Any.hashCode
: http : //www.scala-lang.org/api/rc/scala/Any.html
这个答案显示了一个自定义的可变集合与用户定义的平等 。 通过用Vector
replace内部存储并在每次操作时返回自身的修改副本,可以使其不可变
“直接覆盖==是不可能的,因为它被定义为类Any中的最后一个方法。也就是说,Scala将==视为在类Any中定义如下:
final def == (that: Any): Boolean = if (null eq this) {null eq that} else {this equals that}
“从编程斯卡拉,第二版