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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7681183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 03:32:45  来源:igfitidea点击:

How can I define a custom equality operation that will be used by immutable Set comparison methods

scalasetoverriding

提问by Kareem

I have an immutable Set of a class, Set[MyClass], and I want to use the Set methods intersect and diff, but I want them to test for equality using my custom equals method, rather than default object equality test

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

I have tried overriding the == operator, but it isn't being used.

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

Thanks in advance.

提前致谢。

Edit:

编辑:

The intersect method is a concrete value member of GenSetLike

intersect 方法是 GenSetLike 的具体值成员

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

规范:http: //www.scala-lang.org/api/current/scala/collection/GenSetLike.htmlsrc: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

过滤器在 TraversableLike 中定义

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

规范: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

源代码: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
}

What's unclear to me is what it uses when invoked without a predicate, p. That's not an implicit parameter.

我不清楚的是它在没有谓词的情况下调用时使用什么,p。这不是隐式参数。

回答by Didier Dupont

equals and hashCode are provided automatically in case class only if you do not define them.

仅当您未定义它们时,才会在 case class 中自动提供 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))

If what you want is reference equality, still write equals and hashCode, to prevent automatic generation, and call the version from AnyRef

如果你要的是引用相等,还​​是写equals和hashCode,防止自动生成,从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 Setcalls, so it is useless here and quite dangerous in general.

您不能覆盖==(o: Any)来自 AnyRef 的,它是密封的并且总是调用 equals。如果你尝试定义一个 new (overloaded) ==(m: MyClass),它不是Set调用的那个,所以它在这里没用,而且通常很危险。

As for the call to filter, the reason it works is that Set[A]is a Function[A, Boolean]. And yes, equalsis used, you will see that function implementation (apply) is a synonymous for contains, and most implementations of Setuse ==in contains (SortedSetuses the Orderinginstead). And ==calls equals.

至于对 的调用filter,它起作用的原因是它Set[A]是一个Function[A, Boolean]. 是的,equals在使用时,你会看到函数实现(apply)是一个代名词contains,和大多数实现Set使用==在包含(SortedSet使用Ordering替代)。并==调用equals



Note: the implementation of my first equalsis 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 canEqualmethod (you may read this blogby Daniel Sobral)

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

回答by Ben

You'll need to override .hashCodeas well. This is almost always the case when you override .equals, as .hashCodeis often used as a cheaper pre-check for .equals; any two objects which are equal musthave identical hash codes. I'm guessing you're using objects whose default hashCodedoes not respect this property with respect to your custom equality, and the Set implementation is making assumptions based on the hash codes (and so never even calling your equality operation).

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

See the Scala docs for Any.equalsand Any.hashCode: http://www.scala-lang.org/api/rc/scala/Any.html

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

回答by Ben Hutchison

This answer shows a custom mutable Set with user-defined Equality. It could be made immutable by replacing the internal store with a Vectorand returning a modified copy of itself upon each operation

这个答案显示了一个自定义的可变 Set 与用户定义的 Equality。可以通过用 a 替换内部存储Vector并在每次操作时返回其自身的修改副本来使其不可变

回答by t. fochtman

"It is not possible to override == directly, as it is defined as a final method in class Any. That is, Scala treats == as if were defined as follows in class Any:

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

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

" from Programming In Scala, Second Edition

” 摘自 Scala 编程,第二版