与自定义组合/运算符匹配

时间:2011-07-18 19:51:08

标签: scala pattern-matching

我知道您可以像

那样在列表上进行匹配
val list = List(1,2,3)
list match {
  case head::tail => head
  case _ => //whatever
}

所以我开始想知道它是如何工作的。如果我理解正确,::只是一个操作符,那么阻止我做什么就像

4 match {
  case x + 2 => x //I would expect x=2 here
}

如果有办法创建这种功能,它是如何完成的;如果没有,为什么呢?

3 个答案:

答案 0 :(得分:8)

模式匹配接受输入并使用unapply函数对其进行分解。因此,在您的情况下,unapply(4)必须返回总和为4的两个数字。但是,有许多对总和为4,因此函数不知道该怎么做。

您需要的是2能够以某种方式访问​​unapply功能。存储2的特殊案例类适用于此:

case class Sum(addto: Int) {
    def unapply(i: Int) = Some(i - addto)
}

val Sum2 = Sum(2)
val Sum2(x) = 5  // x = 3

(能够为val Sum(2)(y) = 5执行紧凑性操作会很好,但Scala不允许参数化提取器;请参阅here。)

[编辑:这有点傻,但你实际上也可以做到以下几点:

val `2 +` = Sum(2)
val `2 +`(y) = 5  // y = 3

编辑:head::tail的工作原理是,只有一种方法可以将头部从列表尾部分割出来。

::+没有任何内在的特殊关系:如果您对预期如何打破数字有预先确定的想法,可以使用+。例如,如果您希望+表示“分成两半”,那么您可以执行以下操作:

object + {
    def unapply(i: Int) = Some(i-i/2, i/2)
}

并使用它:

scala> val a + b = 4
a: Int = 2
b: Int = 2

scala> val c + d = 5
c: Int = 3
d: Int = 2

编辑:最后,this解释说,在模式匹配时,A op Bop(A,B)的含义相同,这使得语法看起来不错。

答案 1 :(得分:4)

case head :: tail匹配使用p1 op p2形式的中缀操作模式,在进行实际匹配之前将其转换为op(p1, p2)。 (有关::

,请参阅API

+的问题如下:

虽然很容易添加

object + { 
  def unapply(value: Int): Option[(Int, Int)] = // ...
}

进行匹配的对象,每个值只能提供一个结果。 E.g。

object + { 
  def unapply(value: Int): Option[(Int, Int)] = value match {
    case 0 => Some(0, 0)
    case 4 => Some(3, 1)
    case _ => None
}

现在可行:

0 match { case x + 0 => x } // returns 0

也是这个

4 match { case x + 1 => x } // returns 3

但这不会,你无法改变它:

4 match { case x + 2 => x } // does not match

::没有问题,因为它始终定义为head以及列表的tail是什么。

答案 2 :(得分:1)

Scala中有两个:: s(发音为“cons”)。一个是List s上的运算符,另一个是类,它表示以头和尾为特征的非空列表。所以head :: tail是构造函数模式,与运算符无关。