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

时间:2011-10-06 22:25:57

标签: scala set override

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

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

提前致谢。

编辑:

intersect方法是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

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

又一个编辑:

过滤器在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。这不是一个隐含的参数。

4 个答案:

答案 0 :(得分:50)

仅当您没有定义它们时,才会在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),AnyRef是密封的并且总是调用equals。如果你尝试定义一个新的(重载的)==(m: MyClass),它不是Set调用的那个,所以它在这里没用,而且一般来说非常危险。

至于filter的来电,其工作原因是Set[A]Function[A, Boolean]。是的,使用equals,您会看到函数实现(apply)是contains的同义词,Set的大多数实现都使用==包含(SortedSet使用Ordering代替)。 ==调用equals


注意:我的第一个equals的实现很快而且很脏,如果MyClass要被子类化,可能会很糟糕。如果是这样,您至少应检查类型相等(this.getClass == that.getClass)或更好地定义canEqual方法(您可以阅读Daniel Sobral的this blog

答案 1 :(得分:8)

您还需要覆盖.hashCode。当您覆盖.equals时,情况几乎总是如此,因为.hashCode通常被用作.equals的更便宜的预检;任何两个相等的对象必须具有相同的哈希码。我猜你正在使用默认hashCode不尊重这个属性的对象与你的自定义相等,并且Set实现基于哈希码做出假设(所以从来没有调用你的相等操作)

请参阅Any.equalsAny.hashCode的Scala文档:http://www.scala-lang.org/api/rc/scala/Any.html

答案 2 :(得分:1)

This answer shows a custom mutable Set with user-defined Equality。可以通过用Vector替换内部存储并在每次操作时返回自身的修改副本来使其不可变

答案 3 :(得分:0)

&#34;无法直接覆盖==,因为它被定义为Any类中的最终方法。也就是说,Scala将==视为在Any类中定义如下:

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

&#34;来自Scala编程,第二版