[英]Scala fails to initialize a val
我在下面的Scala程序中发现了一种奇怪的东西(很抱歉包含所有代码,但你会明白我为什么要添加它):
object md2html extends App {
private val DEFAULT_THEME = Themes.AMAZON_LIGHT
private val VALID_OPTIONS = Set("editorTheme", "logo", "style")
try {
// some code 1
} catch {
case t: Throwable => t.printStackTrace(); exitWithError(t.getMessage)
}
// some code 2 (method definitions only)
private def parseOption(key: String, value: String) = {
println(key + " " + VALID_OPTIONS)
if (! Set("theme","editorTheme", "logo", "style").contains(key)) exitWithError(s"$key is not a valid option")
if (key == "theme") Themes(value).toMap else Map(key.drop(2) -> value)
}
// some code 3 (method definitions only)
}
如果在some code...
之一之后定义了VALID_OPTIONS
,则在parseOption
其评估为null。 我认为没有充分的理由。 为了清晰起见,我截断了代码,但如果需要更多代码,我将很乐意添加它。
编辑:我看了一下,这是我发现的。
扩展App
,不会使用此代码初始化val
object Test extends App {
printTest()
def printTest = println(test)
val test = "test"
}
使用常规main方法,它工作正常:
object Test {
def main(args: Array[String]): Unit = {
printTest
}
def printTest = println(test)
val test = "test"
}
我监督过你使用extends App
。 不幸的是,这是Scala的另一个陷阱:
object Foo extends App {
val bar = "bar"
}
Foo.bar // null!
Foo.main(Array())
Foo.bar // now initialized
该App
特点推迟对象的初始化到的调用main
方法,因此,所有的val
s为null
,直到main
方法被调用。
总之, App
trait和val
s混合不好。 我多次陷入陷阱。 如果您使用App
,请避免使用val
,如果必须使用全局状态,请改用lazy val
。
构造函数体,也适用于单例对象,从上到下严格评估。 遗憾的是,这是Scala中常见的陷阱,因为如果在构造函数的其他位置引用了val
s,那么它就变得相关。
object Foo {
val rab = useBar // oops, involuntarily referring to uninitialized val
val bar = "bar"
def useBar: String = bar.reverse
}
Foo // NPE
当然,在一个更好的世界中,Scala编译器要么不允许上面的代码,重新排序初始化,要么至少警告你。 但它不......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.