【问题标题】:Matching with custom combinations/operators与自定义组合/运算符匹配
【发布时间】:2011-07-18 19:51:08
【问题描述】:

我知道您可以通过以下方式对列表进行匹配

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
}

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

【问题讨论】:

  • 你为什么不使用y-2(当y = 4时)?
  • 这更像是一种好奇心,所以我没有任何具体的例子,但我认为这对于更复杂的类来说很好。

标签: scala pattern-matching


【解决方案1】:

模式匹配接受输入并使用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) 的含义相同,这使得语法看起来不错。

【讨论】:

  • 我认为你的编辑让我明白了,今晚晚些时候我将不得不玩弄这个概念
  • @Dylan:我重写了散文,希望现在不会那么混乱。
【解决方案2】:

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

+ 的问题如下:

虽然很容易添加一个

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

进行匹配的对象,您只能为每个值提供一个结果。例如

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

不过,:: 没问题,因为它总是定义了列表中的 headtail 是什么。

【讨论】:

  • API 链接 +1 - 我没有意识到这一点。因此,据我所知, List[_] 实际上是 :: 的子类,因此是案例类,这就是为什么您可以这样匹配?因此,如果我想提供某种匹配,例如"hello" match { case head::tail //h + ello ...,那么我需要将 String 隐式转换为我自己的专用案例类?
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2018-09-14
    • 2018-01-21
    • 2018-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-20
    • 2017-01-12
    相关资源
    最近更新 更多