如何定义不可变的 Set 比较方法将使用的自定义相等操作 [英] How can I define a custom equality operation that will be used by immutable Set comparison methods

查看:19
本文介绍了如何定义不可变的 Set 比较方法将使用的自定义相等操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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

提前致谢.

intersect方法是GenSetLike的具体值成员

The intersect method is a concrete value member of GenSetLike

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

又一个

过滤器在 TraversableLike 中定义

filter is defined in 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.这不是隐式参数.

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

推荐答案

equals 和 hashCode 仅在您未定义它们的情况下才会在 case 类中自动提供.

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))

如果你要的是引用相等,还​​是写equals和hashCode,防止自动生成,从AnyRef调用版本

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

这样:

Set(MyClass("x"), MyClass("x"))
res2: scala.collection.immutable.Set[MyClass] = Set(MyClass(x), MyClass(x))

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

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.

对于filter的调用,之所以起作用,是因为Set[A]是一个Function[A, Boolean].是的,使用了 equals,你会看到函数实现 (apply) 是 contains 的同义词,而大多数 的实现Set 在 contains 中使用 ==(SortedSet 使用 Ordering 代替).== 调用 equals.

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.

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆