我有一个案例类Pair(a: Int, b: Int)
,它代表一对2个整数。为了获得Pair(2, 5) == Pair(5, 2)
,我将equals
方法覆盖如下。
override def equals(that: Any): Boolean = that match {
case Corner(c, d) => (a == c && b == d) || (a == d && b == c)
case _ => false
}
现在等式成立,Pair(2, 5) == Pair(5, 2)
返回true,就像我想要的那样。但是,这在模式匹配时不起作用:
Pair(2, 5) match {
case Pair(5, 2) => print("This is what I want")
case _ => print("But this is what I get")
}
有人可以帮助我吗?可以/我应该这样做吗?有哪些替代方案?每次我与对模式匹配时,我都不想写case Pair(2, 5) | case(5, 2) =>
。
答案 0 :(得分:5)
简答:
那是行不通的。你可以像这样重写你的陈述:
Pair(2, 5) match {
case that if that == Pair(5, 2) => println("This is what I want")
case _ => println("nope")
}
答案很长:
当你在案例类match
时,它没有使用equals
;它实际上是使用伴侣对象的unapply
方法。实际上,scala的match/case
语句背后的大部分“魔法”都归结为unapply
。
当你写case class Pair(a: Int, b: Int)
时,你可以免费获得很多东西。其中一个是an extractor,例如:
object Pair {
def unapply(pair: Pair): Option[(Int, Int)] = {
Some((pair.a, pair.b))
}
}
因此,当您说pair match { case Pair(a, b) => ... }
时,编译器会认为Pair.unapply(pair)
,然后将a
分配给结果元组的_1
位置中的值,并指定{{1} } {到} b
位置的值。 (如果_2
返回Pair.unapply(pair)
,则该情况会失败。
基本上,您只能从提取器的每个输入获得一个特定值,但您要查找的内容需要两个。
答案 1 :(得分:1)
我说这个案例的一个好方法可能不是覆盖equals
,而是禁止无序对:
case class Pair(a: Int, b: Int) {
assert(a <= b, s"First parameter of Pair($a, $b) must be less or equal to the second")
}
object Pair {
def of(a: Int, b: Int) = if (a <= b) Pair(a, b) else Pair(b, a)
}
非常不幸的是,Scala不允许&#34;覆盖&#34;案例类的伴随对象中的apply
方法,否则这将是一个非常透明的解决方案。
答案 2 :(得分:0)
如Alexey Romanov所述,无法覆盖案例类的unapply方法。但是,在我的情况下,我并不需要Pair
作为案例类,所以首先我这样做了:
class Pair(val a: Int, val b: Int)
object Pair {
def apply(a: Int, b: Int) = new Pair(a, b)
def unapply(arg: Pair): Option[(Int, Int)] = {
if (arg.a < arg.b)
Some(arg.a, arg.b)
else
Some(arg.b, arg.a)
}
}
Pair(5, 2) match {
case Pair(3, 4) => "It's dumb"
case Pair (2, 5) => "Matched!"
case _ => "Doesn't work"
}
Pair(2, 5) match {
case Pair(3, 4) => "It's dumb"
case Pair (2, 5) => "Matched!"
case _ => "Doesn't work"
}
Pair(2, 5) match {
case Pair(4, 3) => "It's dumb"
case Pair(5, 2) => "Doesn't match!"
case _ => "Should have written the digits in ascending order!"
}
可以看出,它并不完美 - 我仍然要确保用升序编写我的匹配案例。但是,一旦我意识到通过简单断言值在构造函数中排序,我可以使equals
方法更短,并使apply
方法处理排序,或者只是做Alexey Romanov建议,这就是我将答案标记为已接受答案的原因。