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

可以在scala匹配器中使用算术吗?,scala,pattern-matching,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未找到:值+ 等价物1: def MatchSmth(s

以代码为例:

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未找到:值+

等价物1:

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
 }
等价物2:

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不允许在matchers中使用这种构造(使用算术)?

您可以编写

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

8.1模式 如您所见,允许使用
literal
(8.1.4 literal模式)或
StableId
(8.1.5稳定标识符模式),而不是常量表达式。你现在可以问,为什么不允许常量表达式,有什么重要的原因吗?如果允许常量表达式,语法是否仍然可以明确地工作?我不知道。

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

概念理性 从概念上讲,模式匹配的思想不是为if-then-else或求解方程提供一个很好的捷径,而是提供使用分解结构定义部分函数,类似于。对于这个任务,Scala使用所谓的“提取器”

提取器是构造函数的反面。从技术上讲,Scala使用“unapply”方法分解给定对象的各个部分。Unapply获取对象并返回布尔值、可选原子值或可选元组。另外,还有unplyseq,它可以返回一系列值。Scala然后尝试将结果与给定的参数列表匹配。如果可以进行匹配,Scala会将原子值或元组的一部分与给定的参数名取消匹配。(有关更多详细信息,请参阅)

例如:

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)
。然后,它会将该对象赋予在
匹配之后定义的分部函数。此函数将调用该对象上的
Pet.unapply(…)
,并检查结果是否为
Some(Tuple[Int,u])
形状。如果为true,它将把变量
name
绑定到该元组的第一个成员,并使用
println
函数调用给定的操作

Scala只检查
结果的形状。从理论上讲,它可以投入更多的精力来尝试将不适用的结果与给定的变量统一起来。这在像您的示例中这样的简单情况下会有所帮助。但在更复杂的情况下,它会带来巨大的运行时损失。从理论上讲,统一甚至可能是一个无止境的循环

摘要(tl;dr)
Match不是一个花哨的if,而是使用解构。它没有在统一方面做出任何努力,而是采用“原样”的术语。这对于保持生成的代码快速是必要的

这篇文章应该是问题1的答案。很好,很简单,很明显。但我对更复杂的算术运算的理论解感兴趣,所以Suma的答案更适合我。如果可以的话,我会选择两者。stefan.schwetschke的答案更完整,但你的答案也很好。你能再解释一下什么是“统一”,以及为什么统一可以针对文字而不是表达式的结果来实现吗?统一是Prolog为匹配两个术语所做的工作。维基百科有一个很好的解释:统一是一个伟大的抽象工具。不幸的是,它带来了巨大的运行时惩罚(在某些情况下,它永远不会结束)。即使在阅读之后,我也看不到这种情况下的运行时惩罚。我们在这里讨论的只是文字、具有已知值的变量和函数调用的组合。所有这些都可以用正常的方式进行计算,就像执行程序一样。当与计算结果统一或与变量值统一(这已经是可能的)时,我看不到任何差异。我理解定义语法可能不是一件小事,而且由于用例不是很重要,所以不太可能发生。但我不相信运行时惩罚是原因。@Suma:你的案子很好,没有运行时惩罚。但稍微有用的案例会带来巨大的惩罚。因此,此功能仅对非常简单的情况有用,而对稍微复杂的情况则无效。即使将统一限制在算术情况下,也很容易遇到Scala无法轻松解决的复杂情况。
case class Pet(name: String, age : Int)
Pet("Polly", 86) match {
   case Pet(name, _) => println(s"Hello ${name}")
}
// This will print: Hello Polly