繁体   English   中英

Scala:如何覆盖任意元素类型的元组 equals() 方法?

[英]Scala: How to override tuple equals() method for arbitrary element types?

我有一张地图,其中的值以元组为键。 在我的情况下,无论元素顺序如何,我都需要元组匹配,因此,例如,我需要保持:

(1, 2) == (2, 1) is true

如何覆盖元组equals运算符,因此对于任何类型 X, Y :

(a:X, b:Y) == (b:Y, a:X) is true  ?   

稍后更正:另一个想法是编写我自己的具有所需行为的Pair类。 在这种情况下, equals()覆盖会是什么样子?

当然,您真的不想更改元组的语义,因为宇宙会内爆。 你只是想是这样的元组-除了他们平等的语义。

为什么不只使用案例类? 元组实际上只是现成的类,当定义一个类不值得麻烦时,它可以将一些东西放在一起。 好吧,如果你想改变平等,我会说这是值得的! 此外,您可以使用比 _1 和 _2 更有意义的名称。

当然,我不知道这些名字是什么,但这里有一些代码。 正如 Travis 指出的那样,处理相等性很棘手,部分原因是您还必须考虑哈希码。 希望这是合理的:

scala> case class Foo[T]( a:T, b:T ) {
  override def equals( that:Any ) = that match {
    case that:Foo[T] => ( that canEqual this ) && (
      this.a == that.a && this.b == that.b ||
      this.a == that.b && this.b == that.a
    )
    case _ => false
  }
  override def canEqual( that:Any ) = that.isInstanceOf[Foo[T]]
  override def hashCode = a.hashCode + b.hashCode
}
defined class Foo

scala> Foo(1,2) == Foo(1,2)
res15: Boolean = true

scala> Foo(1,2) == Foo(2,1)
res16: Boolean = true

scala> Foo(1,2) == Foo(2,2)
res17: Boolean = false

scala> collection.immutable.HashSet( Foo(0,1), Foo(1,0), Foo(1,2) )
res18: scala.collection.immutable.HashSet[Foo[Int]] = Set(Foo(0,1), Foo(1,2))

请注意,由于相等的定义, res18包含Foo(1,0)但不包含Foo(1,0) Foo(0,1)

好吧,您不能覆盖为Tuple2定义的行为。 毕竟,这两个元组相等,因此您不能告诉 Scala 说它们相等。

您可以定义您自己的具有您想要的相等属性的元组类型,但是您将无法使用漂亮的括号语法。

最简单的方法是定义您自己调用的相等函数:

 def myEquals[X,Y](a: (X,Y), b: (Y,X)) = a._1 == b._2 && a._2 == b._1

那么你有:

 scala> myEquals((1,'a'), ('a',1))
 res0: Boolean = true

您还可以为 Tuple2 定义一个新的相等运算符

implicit class NewEqualityTuple2[X,Y](a: (X,Y)) {
  def =<>=(b: (Y,X)) = a._1 == b._2 && a._2 == b._1
}

给这个:

scala> (1,'a') =<>= ('a',1)
res1: Boolean = true

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM