参数表上组合的Scala模式匹配

参数表上组合的Scala模式匹配,scala,parameters,pattern-matching,Scala,Parameters,Pattern Matching,我有一个case类对(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(

我有一个case类
对(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")
}

谁能帮我一下吗?我能/应该这样做吗?有哪些替代方案?我真的不想每次用配对模式匹配时都写
案例对(2,5)|案例(5,2)=>

简短回答:
那是行不通的。不过,您可以像这样修改您的声明:

Pair(2, 5) match {
  case that if that == Pair(5, 2) => println("This is what I want")
  case _ => println("nope")
}
详细回答:
当您对case类进行
匹配时,它没有使用
equals
;它实际上使用了同伴对象的
方法。事实上,scala的
match/case
语句背后的绝大多数“魔力”都归结为
unapply

当您编写
案例类对(a:Int,b:Int)
时,您可以免费获得很多东西。其中之一是,例如:

因此,当你说
pair match{case pair(a,b)=>…}
时,编译器认为
pair.unapply(pair)
,然后将
a
赋值给结果元组
\u 1
位置的值,并将
b
赋值给
\u 2
位置的值。(如果
Pair.unapply(Pair)
返回
None
,则案例将失败)


基本上,从提取器中每次输入只能获得一个特定值,但您要查找的是两个值。

我想说,对于这种情况,一个好的解决方案可能不是重写
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)
}
案例类对(a:Int,b:Int){
assert(a如上所述,不可能重写case类的unapply方法。但是,在我的情况下,我不一定需要将
Pair
作为case类,因此首先我做了以下工作:

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!"
}
类对(val a:Int,val b:Int)
对象对{
def apply(a:Int,b:Int)=新对(a,b)
取消应用def(参数:对):选项[(Int,Int)]={
if(参数a<参数b)
一些(参数a、参数b)
其他的
一些(参数b、参数a)
}
}
配对(5,2)匹配{
案例对(3,4)=>“它是哑的”
案例对(2,5)=>“匹配!”
案例=>“不起作用”
}
配对(2,5)匹配{
案例对(3,4)=>“它是哑的”
案例对(2,5)=>“匹配!”
案例=>“不起作用”
}
配对(2,5)匹配{
案例对(4,3)=>“它是哑的”
案例对(5,2)=>“不匹配!”
case=>“应该按升序写入数字!”
}

可以看出,它并不完美–我仍然必须确保以升序编写匹配案例。然而,一旦我意识到,只要断言值在构造函数中是有序的,我就可以缩短
equals
方法,并让
apply
方法负责排序,或者我们必须按照建议去做,这就是为什么我将他的答案标记为已接受的答案。

注意,实现
equals
的类也必须重写
hashCode
,以使相同的实例始终具有相同的hash代码(这也适用于您的原始问题).
case class
会自动处理此一致性(前提是所有参数本身在这方面都是正确的)。我最终使用的就是这个相关问题的答案–我强烈建议任何人也看到这一点。
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!"
}