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

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

问题描述

我有一个不可变的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

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
}

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

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