我正在学习Scala基础知识。我刚刚遇到lazy val
概念。我有以下代码片段,没有错误/警告
lazy val a = 10 + b
lazy val b = 5
println(a)
<案例2
lazy val a = 10 + b
val b = 5
println(a)
<案例3
val a = 10 + b
lazy val b = 5
println(a)
我理解case 1 & 2
的工作原理。但我不明白case 3
中的代码如何正常工作而没有错误/警告。当a
尚未定义时,Scala如何评估b
的值?
我没有在Scala REPL
中运行此代码。我已将案例3中的代码保存在名为lazyVal.scala
的文件中。我正在使用scala lazyVal.scala
执行它。我认为scala会解释文件中的代码。
如果我将lazyVal.scala
中的代码更改为
val a = 10 + b
val b = 5
println(a)
使用scala lazyVal.scala
执行它我会收到警告
/Users/varun.risbud/scalaRepo/src/Chapter1/lazyVal.scala:1: warning: Reference to uninitialized value b
val a = 10 + b
^
one warning found
10
此外,如果我将代码更改为创建对象并扩展App,则可以使用
object lazyVal extends App {
val a = 10 + b
lazy val b = 5
println(a)
}
➜ Chapter1 scalac lazyVal.scala
➜ Chapter1 scala lazyVal
15
我的scala version
是2.12.1
,如果这有任何区别的话。
答案 0 :(得分:5)
构造函数中的语句以文本顺序执行,这就是当a
的初始化引用未初始化的b
时收到警告的原因。以你甚至没有得到警告的方式撰写课程是一个常见的错误。 (这里有一个FAQ教程。)
在本地语句序列中禁止使用相同的文本:
scala> :pa
// Entering paste mode (ctrl-D to finish)
locally {
val a = 10 + b
lazy val b = 5
println(a)
}
// Exiting paste mode, now interpreting.
<console>:13: error: forward reference extends over definition of value a
val a = 10 + b
^
作为类或对象的成员,在构造期间评估a
时,“按需”评估惰性成员。
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X {
val a = 10 + b
lazy val b = 5
println(a)
}
// Exiting paste mode, now interpreting.
defined object X
scala> X
15
res1: X.type = X$@6a9344f5
脚本运行器以这种方式打包您的代码行:
object X {
def main(args: Array[String]): Unit =
new AnyRef {
val a = 10 + b
lazy val b = 5
println(a)
}
}
如果你给它一个main
或扩展App
的对象,它将不会包装代码,而只是直接使用它。
三种配方之间存在细微差别。例如,顶级对象的构造函数作为静态初始化程序运行;但是App
是特殊的,可以将初始化代码作为main
运行。 (他们正在摆脱App
,因为它令人困惑。)