在为数字文字赋值时,Scala不会出现编译时错误?

时间:2016-03-19 13:14:08

标签: scala runtime-error

在学习scala时,我偶然发现了以下奇怪的片段:

package temptests

object TempTest {
  //def 2 = 123 // does not compile
  val 2 = 123 // compiles, but leads to an exception at runtime

  def main(args: Array[String]) = { // just do something to load this class
    println("Hello")
  }
}

我希望编译器会在val 2 = 123上抛出错误,因为标识符不能以数字开头,但代码编译时没有警告。 但是,在运行时它会立即抛出异常:

  

线程“main”中的异常java.lang.ExceptionInInitializerError at   temptests.TempTest.main(TempTest.scala)at   sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at   sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     在   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     在java.lang.reflect.Method.invoke(Method.java:498)at   com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)   引起:scala.MatchError:123(类java.lang.Integer)at   temptests.TempTest $。(TempTest.scala:5)at   temptests.TempTest $。(TempTest.scala)... 6更多

我很好奇:val 2 = 123如何理解Scala?为什么没有编译时错误?

2 个答案:

答案 0 :(得分:12)

  

我只是很好奇:Scala如何理解val 2 = 123

您可以将val 2 = 123视为:

123 match {
    case 2 => 2
}

Scala中的变量名称部分并不总是简单的名称,它也可以是模式,例如:

val (x, y) = (1, 2)

将1和2分别分解为x和y。在scala中, case 语句之后允许的所有内容也在 val 之后被允许并转换为模式匹配。

From the specification(强调我的):

  

值定义可以选择一个模式作为左侧。   如果 p是某种模式,而不是简单的名称或名称后跟a   冒号和类型,然后将值定义val p = e扩展为   如下:

(跳至相关示例):

  

如果p具有唯一的绑定变量x:

val x = e match { case p => x }

这是编译器不发出编译时错误的原因。在google group question中对这个主题进行了长时间的讨论。

答案 1 :(得分:3)

val声明的左侧可以是模式。请参阅DelimitedSplit8K

所以

val 2 = 123

可以写成

123 match {
  case 2 => 2
}

给出匹配错误。

在现实生活中,这主要用于将元组提取到可读的局部值:

val test = ("Foo", 30)
val (name, age) = test