在学习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
?为什么没有编译时错误?
答案 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