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

Why does pattern matching in Scala not work with variables?

提问人:Henry Henrinson 提问时间:8/16/2011 更新时间:12/19/2020 访问量:39921

问:

采用以下函数:

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. 为什么会有这种行为?难道不能只在作用域中查找具有适当类型的现有变量并首先使用这些变量,如果找不到,则将目标视为要进行模式匹配的名称吗?

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

Scala 模式匹配匹配

评论

0赞 Dave L. 4/21/2013
相关新闻: stackoverflow.com/questions/7083502/...
3赞 conny 6/27/2017
我相信这个问题、代码和答案在 Scala 2.12.x 中已经过时了。如果将适用的版本作为问题的一部分提及,那就太好了。

答:

258赞 Ben James 8/16/2011 #1

你要找的是一个稳定的标识符。在 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")
    }
}

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

评论

5赞 Emil Ivanov 8/16/2011
我敢打赌这来自 Erlang,其中变量以大写字母开头,符号以小写字母开头。
12赞 Luigi Plinge 8/16/2011
请注意,这是一个值 (),而不是变量 ()。它不适用于变量。targetvalvar
15赞 Daniel C. Sobral 8/17/2011
@Emil 实际上,Scala 中的大写标识符表示常量。因此,大写标识符上的模式匹配被视为与常量进行比较的意思。它对诸如 ,敢打赌这是真正的原因。Nil
0赞 Nader Ghanbari 10/12/2018
似乎不能用作稳定的标识符来与它进行模式匹配,唯一的方法似乎是使用像 .可能是一个语法限制,否则它应该至少在语义上工作。thiscase x if x == this =>object
0赞 Warbo 10/15/2020
此规则还使得隐藏不需要的变量变得容易,例如NonEmptyList.from(list) match { case None => Left("List was empty"); case Some(list) => /* Re-use the name 'list' for the NonEmptyList, so the original List can't be referenced accidentally */ }
2赞 Raptor0009 12/19/2020 #2

您也可以将其分配给案例中的临时变量,然后进行比较,这也有效

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