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

时间:2016-06-27 20:07:18

标签: scala parameters pattern-matching

我有一个案例类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) =>

3 个答案:

答案 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建议,这就是我将答案标记为已接受答案的原因。