是否可以在 Scala 匹配器中使用算术?
Is it possible to use arithmetic in scala matchers?
考虑代码:
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 +
等效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 不允许在匹配器中进行这种构造(使用算术)?
你可以写
def MatchSmth(someInt: Int, offset: Int = 1): Int = {
(someInt - offset) match {
case 3 => 123123
case 4 => 22
case 5 => 123
case _ => -1
}
}
没有。模式的 Scala grammar 是:
8.1 Patterns
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 稳定标识符模式)是允许的,而不是常量表达式。您现在可以问 - 是否有一些重要原因不允许常量表达式?如果允许常量表达式,语法是否仍然可以明确地工作?那个我不知道。
技术原因
从技术上讲,Scala 在其规范中不允许这样做。这已在 .
中描述
概念原因
从概念上讲,模式匹配的想法不是成为 if-then-else 的捷径或求解方程,而是提供使用解构定义的偏函数,类似于 Lisp。对于这个任务,Scala 使用所谓的 "extractors".
抽取器与构造器有点相反。从技术上讲,Scala 使用方法 "unapply" 将给定的对象分解为多个部分。 Unapply 接受对象和 returns 一个布尔值、一个可选的原子值或一个可选的元组。或者还有 unapplySeq,它可以 return 一个值序列。 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,_])
的形状。如果为真,它将变量 name
绑定到该元组的第一个成员,并使用 println
函数调用给定的操作。
Scala 只检查 unapply
结果的形状。从理论上讲,它可以付出更多的努力来尝试将 unapply 的结果与给定的变量统一起来。这将有助于简单的情况,例如您的示例中的情况。但在更复杂的情况下,它会带来巨大的运行时间损失。理论上,统一甚至可以无限循环。
摘要 (tl;dr)
Match不是花哨的if,而是使用了解构。它并没有在统一上付出任何努力,而是采用了术语 "as-is"。这是保持生成代码快速的必要条件。
考虑代码:
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 +
等效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 不允许在匹配器中进行这种构造(使用算术)?
你可以写
def MatchSmth(someInt: Int, offset: Int = 1): Int = {
(someInt - offset) match {
case 3 => 123123
case 4 => 22
case 5 => 123
case _ => -1
}
}
没有。模式的 Scala grammar 是:
8.1 Patterns
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 稳定标识符模式)是允许的,而不是常量表达式。您现在可以问 - 是否有一些重要原因不允许常量表达式?如果允许常量表达式,语法是否仍然可以明确地工作?那个我不知道。
技术原因
从技术上讲,Scala 在其规范中不允许这样做。这已在
概念原因
从概念上讲,模式匹配的想法不是成为 if-then-else 的捷径或求解方程,而是提供使用解构定义的偏函数,类似于 Lisp。对于这个任务,Scala 使用所谓的 "extractors".
抽取器与构造器有点相反。从技术上讲,Scala 使用方法 "unapply" 将给定的对象分解为多个部分。 Unapply 接受对象和 returns 一个布尔值、一个可选的原子值或一个可选的元组。或者还有 unapplySeq,它可以 return 一个值序列。 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,_])
的形状。如果为真,它将变量 name
绑定到该元组的第一个成员,并使用 println
函数调用给定的操作。
Scala 只检查 unapply
结果的形状。从理论上讲,它可以付出更多的努力来尝试将 unapply 的结果与给定的变量统一起来。这将有助于简单的情况,例如您的示例中的情况。但在更复杂的情况下,它会带来巨大的运行时间损失。理论上,统一甚至可以无限循环。
摘要 (tl;dr)
Match不是花哨的if,而是使用了解构。它并没有在统一上付出任何努力,而是采用了术语 "as-is"。这是保持生成代码快速的必要条件。