Scala初始化顺序
在Scala编程(第10章“组合与继承”)一书中,有一个例子引起了一些误解。这是提取的部分:Scala初始化顺序,scala,Scala,在Scala编程(第10章“组合与继承”)一书中,有一个例子引起了一些误解。这是提取的部分: abstract class Element { def contents: Array[String] val someProperty: String = { println("=== Element") contents(0) } } class UniformElement( str: String ) extends Element { val s = s
abstract class Element {
def contents: Array[String]
val someProperty: String = {
println("=== Element")
contents(0)
}
}
class UniformElement(
str: String
) extends Element {
val s = str
println("=== UniformElement.s " + s)
def contents = Array(s) // error
//def contents = Array(str) // ok
}
val e = new UniformElement("str")
println(e.someProperty)
由于某些原因,超类的初始化发生在s
初始化之前:
scala example.scala
=== Element
=== UniformElement.s str
null
为什么没有
s
(请参见代码中的注释行)替代方法可以工作?问题是,在构造函数完成之前,字段值为null
,并且超级构造函数间接引用由子构造函数初始化的值s
,但子构造函数尚未完成。情况是这样的
class UniformElement {
def <init>(str: String) = {
super.<init>()
s = str
}
}
它以前执行过
s = str
通常可以通过将渴望的val s
更改为懒惰的方式来解决问题
class UniformElement(str: String) extends Element {
lazy val s = str
println("=== UniformElement.s " + s)
def contents = Array(s)
}
现在输出什么
=== Element
=== UniformElement.s str
str
谢谢你提出这个有趣的问题!我的猜测(在花了一些时间在Scastie上之后)是以下初始化顺序:
str
是第一个要定义的值元素
制服元素
类统一元素{
//参数初始化
val str=“str”
//超级构造函数
定义内容:数组[字符串]
val someProperty:字符串={
println(“==元素”)
目录(0)
}
//子构造函数
val s=str
println(“==UniformElement.s”+s)
def contents=数组//错误
//def contents=Array(str)//确定
}
诀窍在于,要初始化someProperty
,scala需要计算contents(0)
并找到contents
定义。但在查找定义时,s
尚未定义(而str
是)
因此,最终的“运行时”过程:
类统一元素{
//参数初始化
val str=“str”
//用定义替换内容的超级构造函数
val someProperty:字符串={
println(“==元素”)
数组(0)//错误:s不存在!
//数组(str)(0)//确定:str存在
}
//子构造函数
val s=str
println(“==UniformElement.s”+s)
def contents=数组//错误
//def contents=Array(str)//确定
}
要说服自己,您可以尝试:
println(e.someProperty)//null=>s未定义
println(e.contents(0))//str=>s现在已定义
如果需要,请随时要求澄清
=== Element
=== UniformElement.s str
str