为什么Scala中的模式匹配不适用于变量?


113

具有以下功能:

def fMatch(s: String) = {
    s match {
        case "a" => println("It was a")
        case _ => println("It was something else")
    }
}

这种模式很好地匹配:

scala> fMatch("a")
It was a

scala> fMatch("b")
It was something else

我想做的事情如下:

def mMatch(s: String) = {
    val target: String = "a"
    s match {
        case target => println("It was" + target)
        case _ => println("It was something else")
        }
}

这会产生以下错误:

fMatch: (s: String)Unit
<console>:12: error: unreachable code
               case _ => println("It was something else")

我猜这是因为它认为目标实际上是您想要分配给任何输入的名称。两个问题:

  1. 为什么这样的行为?难道不能仅在范围内查找具有适当类型的现有变量并首先使用它们,如果找不到,然后将target视为模式匹配的名称吗?

  2. 有没有解决方法?有什么方法可以对变量进行模式匹配?最终,人们可以使用一个大的if语句,但是匹配大小写更为优雅。



1
我相信这个问题,代码和答案从Scala 2.12.x开始已经过时了。如果问题所在的部分提到了适用的版本,那将是很好的。
康尼

Answers:


217

您正在寻找的是一个稳定的标识符。在Scala中,这些字符必须以大写字母开头,或者被反引号包围。

这两个都是解决您的问题的方法:

def mMatch(s: String) = {
    val target: String = "a"
    s match {
        case `target` => println("It was" + target)
        case _ => println("It was something else")
    }
}

def mMatch2(s: String) = {
    val Target: String = "a"
    s match {
        case Target => println("It was" + Target)
        case _ => println("It was something else")
    }
}

为了避免意外地引用封闭范围内已经存在的变量,我认为默认行为是将小写模式作为变量而不是稳定的标识符。仅当您看到以大写字母开头或以反勾号开头的内容时,才需要知道它来自周围的范围。


3
我敢打赌,它来自Erlang,其中变量以大写字母开头,符号以小写字母开头。
埃米尔·伊万诺夫

11
注意,这target是一个值(val),而不是变量(var)。它不适用于变量。
路易吉·普林格

大写?FORTRAN的阴影。弱,马丁,虚弱。
马尔沃里奥(Malvolio)

13
@Emil实际上,Scala中的大写标识符表示常量。因此,将与大写标识符匹配的模式视为与常量进行比较。它对诸如之类的东西有很大帮助Nil敢打赌这是真正的原因。
Daniel C. Sobral

似乎不能将其this用作稳定的标识符来对其进行模式匹配,唯一的方法似乎是使用等式保护case x if x == this =>。可能是语法上的限制,否则它应至少在objects 内在语义上起作用。
Nader Ghanbari '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.