Scala中惰性VAL的作用域规则是什么?

Scala中惰性VAL的作用域规则是什么?,scala,scope,sbt,lazy-evaluation,Scala,Scope,Sbt,Lazy Evaluation,我在阅读sbt文档时,在多项目构建一节中遇到了这个示例: import sbt._ import Keys._ object HelloBuild extends Build { lazy val root = Project(id = "hello", base = file(".")) aggregate(foo, bar) lazy val foo = Project(id = "hello-foo",

我在阅读sbt文档时,在多项目构建一节中遇到了这个示例:

import sbt._
import Keys._

object HelloBuild extends Build {
    lazy val root = Project(id = "hello",
                            base = file(".")) aggregate(foo, bar)

    lazy val foo = Project(id = "hello-foo",
                           base = file("foo"))

    lazy val bar = Project(id = "hello-bar",
                           base = file("bar"))
}
我想知道在声明foo和bar之前,如何引用它们?我认为这与lazy关键字有关,但从我的阅读来看,我认为lazy关键字只是延迟了初始化?这里的值似乎在声明之前就在范围内,更不用说初始化了


希望有人能解释这里发生了什么

就像在Java中一样,类实例变量(或scala val)在包含类/对象的任何部分中都“在范围内”,而不管它在哪里声明

也就是说,它不会被引用它并在声明点之前运行的任何代码“初始化”。惰性val的代码不会在其声明的点运行,因此这是安全的。

请参阅:

声明或定义引入的名称的范围是包含绑定的整个语句序列。然而,对块中的前向引用有一个限制:在语句序列s1中。。。构成区块的sn,如果si中的简单名称指sj定义的实体,其中j≥ i、 然后对于si和sj之间的所有sk

  • sk不能是变量定义
  • 如果sk是一个价值定义,那么它一定是懒惰的
换句话说:您可以在惰性VAL上有正向引用,但前提是它们之间没有VAR或非惰性VAL。如果你认为一个懒惰的VAL更像一个方法而不是一个变量,并且在RepL:

上走两个很快的例子,那么这是一种直觉。
scala> object o { val a = b; lazy val c = 6; lazy val b = c }
defined module o

scala> o.a
res1: Int = 6
在第一个示例中,Scala通过调用
b
来计算
a
,后者依次调用
c
,后者的计算结果为
6
。但是在下一个例子中,当
c
不是懒惰的时候

scala> object o { val a = b; val c = 6; lazy val b = c }
defined module o

scala> o.a
res2: Int = 0
当Scala计算
a
时,它调用
b
,返回
c
的当前值(此时为
0
,JVM的默认整数值,因为
c
尚未初始化)。然后
c
随后被初始化,但到那时已经太晚了


另请参见:

精彩的解释!这正是我要寻找的。如果你想一想,这与包含静态变量的Java类和作为静态方法的
lazy VAL
非常相似。它给出了完全相同的结果behavior@Jatin不,惰性VAL是基于实例缓存的。即使实例是一个单例。@som snytt显然是。我的意思是关于行为和初始化这真是个骗局。2008年的搞笑语录:显然人们似乎没有注意到之前关于这个主题的所有信息。我还没有看过“Scala中的编程”的最新草案,但显然它需要用24pt粗体文本讨论初始化,这样人们就不会一遍又一遍地问这个问题。