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

Kar*_*eem 43 overriding scala set

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

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

提前致谢.

编辑:

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
Run Code Online (Sandbox Code Playgroud)

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

另一个编辑:

过滤器在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
}
Run Code Online (Sandbox Code Playgroud)

对我来说不清楚的是它在没有谓词的情况下使用它,p.这不是一个隐含的参数.

Did*_*ont 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))
Run Code Online (Sandbox Code Playgroud)

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

  override def equals(o: Any) = super.equals(o)
  override def hashCode = super.hashCode
Run Code Online (Sandbox Code Playgroud)

接着就,随即:

Set(MyClass("x"), MyClass("x"))
res2: scala.collection.immutable.Set[MyClass] = Set(MyClass(x), MyClass(x))
Run Code Online (Sandbox Code Playgroud)

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

至于呼叫filter,它的工作原理Set[A]是一个Function[A, Boolean].是的,equals使用,您将看到函数implementation(apply)是一个同义词contains,并且大多数Set用于==contains的实现(SortedSet使用Ordering而不是).和==电话equals.


注意:我的第一个实现equals是快速和脏的,如果MyClass要被子类化,可能会很糟糕.如果是这样,你应该至少检查类型equality(this.getClass == that.getClass)或更好地定义一个canEqual方法(你可以阅读Daniel Sobral撰写的这篇博客)


Ben*_*Ben 8

你也需要覆盖.hashCode.当您覆盖时.equals,几乎总是这种情况,因为.hashCode通常用作更便宜的预检.equals; 任何两个相等的对象必须具有相同的哈希码.我猜你正在使用默认hashCode不尊重这个属性的对象与你的自定义相等,而Set实现正在根据哈希码做出假设(因此甚至不会调用你的相等操作).

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