斯卡拉懒惰的解释

时间:2017-08-03 01:29:56

标签: scala lazy-evaluation

我正在学习Scala基础知识。我刚刚遇到lazy val概念。我有以下代码片段,没有错误/警告

<案例1
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 version2.12.1,如果这有任何区别的话。

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,因为它令人困惑。)