是否可以在scala匹配器中使用算术?

时间:2015-01-27 09:52:07

标签: scala pattern-matching

考虑代码:

def MatchSmth(someInt: Int, offset: Int = 1): Int  = {
  someInt match {
    case `offset` + 3 => 123123
    case `offset` + 4 => 22
    case `offset` + 5 => 123
    case invalid => -1
  }
 }

编译错误:scala not found: value +

Equivalent1:

def MatchSmth(someInt: Int, offset: Int = 1): Int  = {
  if (someInt == offset + 3) 123123
  else if (someInt == offset + 4) 22
  else if (someInt == offset + 5) 123
  else -1
 }

Equivalent2:

def MatchSmth(someInt: Int, offset: Int = 1): Int  = {
  someInt match {
    case v if v == `offset` + 3 => 123123
    case v if v == `offset` + 4 => 22
    case v if v == `offset` + 5 => 123
    case invalid => -1
  }
 }

除了equivalent1和equivalent2之外,是否有类似于此代码的内容?为什么Scala不允许在匹配器中使用这种构造(带算术)?

3 个答案:

答案 0 :(得分:2)

技术原因

从技术上讲,Scala不允许在其规范中使用它。这已在answer from Suma中描述。

概念原因

从概念上讲,模式匹配的概念不是if-then-else或解决方程的好捷径,而是使用解构来提供定义部分函数,​​类似于Lisp。对于此任务,Scala使用所谓的"提取器"。

提取器与构造函数相反。从技术上讲,Scala使用方法" unapply"分解其部分中的给定对象。 Unapply接受对象并返回布尔值,可选原子值或可选元组。或者,也有unapplySeq,它可以返回一系列值。然后,Scala尝试将结果与给定的参数列表进行匹配。当匹配可能时,Scala使用给定的参数名称解​​除原子值或元组的一部分。 (有关详细信息,请参阅this paper

示例:

case class Pet(name: String, age : Int)
Pet("Polly", 86) match {
   case Pet(name, _) => println(s"Hello ${name}")
}
// This will print: Hello Polly

Scala将创建一个对象Pet("Polly", 86)。然后它会将该对象赋予match之后定义的部分函数。此函数将调用该对象上的Pet.unapply(...)并检查结果是否为Some(Tuple[Int,_])形状。如果为true,它将变量name绑定到该元组的第一个成员,并使用println函数调用给定的操作。

Scala仅检查unapply结果的形状。从理论上讲,它可以更加努力地尝试将不适用的结果与给定变量统一起来。这有助于简单的情况,例如您的示例中的情况。但在更复杂的情况下,它会带来巨大的运行时惩罚。从理论上讲,统一甚至可以无限循环。

摘要(tl; dr)

如果匹配不是幻想,但使用解构。它并没有在统一方面付出任何努力,而是按照“原样”和#34;进行操作。这对于保持生成的代码很快是必要的。

答案 1 :(得分:1)

你可以写

def MatchSmth(someInt: Int, offset: Int = 1): Int  = {
   (someInt - offset) match {
       case 3 => 123123
       case 4 => 22
       case 5 => 123
       case _ => -1
   }
}

答案 2 :(得分:1)

没有。模式的Scala grammar是:

  

8.1模式

Syntax:
Pattern       ::= Pattern1 { ‘|’ Pattern1 }
Pattern1      ::= varid ‘:’ TypePat
              | ‘_’ ‘:’ TypePat
              | Pattern2
Pattern2      ::= varid [‘@’ Pattern3]
              | Pattern3
Pattern3      ::= SimplePattern
              | SimplePattern {id [nl] SimplePattern}
SimplePattern ::= ‘_’
              | varid
              | Literal
              | StableId
              | StableId ‘(’ [Patterns] ‘)’
              | StableId ‘(’ [Patterns ‘,’] [varid ‘@’] ‘_’ ‘*’ ‘)’
              | ‘(’ [Patterns] ‘)’
              | XmlPattern
Patterns      ::= Pattern {‘,’ Patterns}

如您所见,literal(8.1.4文字模式)或StableId(8.1.5稳定标识符模式)是允许的,而不是常量表达式。您现在可以问 - 是否有一些重要原因导致不允许持续表达?如果允许持续表达,语法是否仍能明确地工作?我不知道。