Scala无法初始化val
我在下面的Scala程序中发现了一些奇怪的地方(很抱歉包含了所有的代码,但您将看到我为什么添加了所有代码): 如果在某个Scala无法初始化val,scala,nullpointerexception,Scala,Nullpointerexception,我在下面的Scala程序中发现了一些奇怪的地方(很抱歉包含了所有的代码,但您将看到我为什么添加了所有代码): 如果在某个some code…之后定义了VALID\u选项,则在parseOption中将其计算为null。我看不出有什么好的理由。为了清晰起见,我截断了代码,但是如果需要更多的代码,我很乐意添加它 编辑:我仔细查看了一下,以下是我的发现 扩展App时,val未使用此代码初始化 object Test extends App { printTest() def print
some code…
之后定义了VALID\u选项
,则在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"
}
构造函数体,这也适用于单例对象,严格地从上到下进行计算。不幸的是,这是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编译器要么不允许上述代码,要么重新排序初始化,要么至少警告您。但它没有…我监督过你使用
扩展应用程序。不幸的是,这是Scala的另一个陷阱:
object Foo extends App {
val bar = "bar"
}
Foo.bar // null!
Foo.main(Array())
Foo.bar // now initialized
App
trait将对象的初始化延迟到调用main
方法,因此在调用main
方法之前,所有val
都是null
总之,App
trait和val
s不能很好地结合。我已经多次落入这个陷阱。如果您使用App
,请避免使用val
s,如果您必须使用全局状态,请使用lazy val
s。如果您正在寻找比Suma和0更具体的原因,则可能重复“必须是初始化顺序”,您需要发布一个足够详细的简单示例,以便可以运行它来重现问题。这不是重复的,因为我还有一个额外的因素:我正在扩展应用程序
哦,对了。我以前在什么地方见过这个。如果没有重复的问题,我会很惊讶。您能否至少添加调用parseOption()
的方式和时间?@DanGetz我试图添加相关的最小代码。嗯,等等,它实际上不太相关,一些代码2
高于val
的第一次使用,那么为什么我在注释下声明它时它仍然计算为null?如果当您将val
更改为lazy val
时NPE消失,我保证您的问题是初始化顺序,而且这可能不是第一眼看到的。这肯定与我正在扩展App
这一事实有关。当然,这与初始化的顺序有关,但在常规的main方法(已测试)中不会发生
object Foo extends App {
val bar = "bar"
}
Foo.bar // null!
Foo.main(Array())
Foo.bar // now initialized