如何定义不可变Set比较方法将使用的自定义相等操作 [英] How can I define a custom equality operation that will be used by immutable Set comparison methods
问题描述
我有一个不可变的Set类,即Set [MyClass],我想使用Set方法相交和差异,但是我希望它们使用自定义的equals方法而不是默认的对象相等性测试来测试是否相等. /p>
我尝试覆盖==运算符,但未使用它.
谢谢.
相交方法是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:解决方案
等于和hashCode仅在case类中自动提供,除非您未定义它们.
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)
,AnyRef是密封的,始终调用equals.如果尝试定义一个新的(重载的)==(m: MyClass)
,它不是Set
调用的那个,因此在这里它是无用的,并且通常很危险.
对于filter
的调用,它起作用的原因是Set[A]
是Function[A, Boolean]
.是的,使用了equals
,您将看到函数实现(apply
)是contains
的同义词,并且Set
的大多数实现都在contains中使用==
(SortedSet
使用Ordering
反而).然后==
调用equals
.
注意:我的第一个equals
的实现是快速而肮脏的,并且如果要对MyClass进行子类化,可能会很糟糕.如果是这样,则至少应检查类型相等性(this.getClass == that.getClass
)或更好地定义canEqual
方法(您可以阅读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
so the intersection is done using the filter method.
Yet another Edit:
filter is defined in TraversableLike
spec: http://www.scala-lang.org/api/current/scala/collection/TraversableLike.html
def filter(p: A => Boolean): Repr = {
val b = newBuilder
for (x <- this)
if (p(x)) b += x
b.result
}
What's unclear to me is what it uses when invoked without a predicate, p. That's not an implicit parameter.
equals and hashCode are provided automatically in case class only if you do not define them.
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))
If what you want is reference equality, still write equals and hashCode, to prevent automatic generation, and call the version from AnyRef
override def equals(o: Any) = super.equals(o)
override def hashCode = super.hashCode
With that:
Set(MyClass("x"), MyClass("x"))
res2: scala.collection.immutable.Set[MyClass] = Set(MyClass(x), MyClass(x))
You cannot override the ==(o: Any)
from AnyRef, which is sealed and always calls equals. If you tried defining a new (overloaded) ==(m: MyClass)
, it is not the one that Set
calls, so it is useless here and quite dangerous in general.
As for the call to filter
, the reason it works is that Set[A]
is a Function[A, Boolean]
. And yes, equals
is used, you will see that function implementation (apply
) is a synonymous for contains
, and most implementations of Set
use ==
in contains (SortedSet
uses the Ordering
instead). And ==
calls equals
.
Note: the implementation of my first equals
is quick and dirty and probably bad if MyClass is to be subclassed . If so, you should at the very least check type equality (this.getClass == that.getClass
) or better define a canEqual
method (you may read this blog by Daniel Sobral)
这篇关于如何定义不可变Set比较方法将使用的自定义相等操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!