3

私は 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 キーワードは初期化を遅らせるだけだと思いましたか? ここでは、初期化を気にせずに、宣言の前でも値が何らかの形で範囲内にあるようです...

うまくいけば、誰かがここで何が起こっているのか説明できます!

4

2 に答える 2

7

Scala 言語仕様の第 4 章を参照してください。

宣言または定義によって導入される名前のスコープは、バインディングを含むステートメント シーケンス全体です。ただし、ブロック内の前方参照には制限があります。ブロックを構成するステートメント シーケンス s 1 ... s nで、s i内の単純な名前がs jで定義されたエンティティを参照する場合、j ≥ i の場合、 s iと s jの間およびそれらを含むすべての s k

  • s kを変数定義にすることはできません。
  • s kが値の定義である場合、それは遅延でなければなりません。

つまり、lazy val で前方参照を行うことができますが、それらの間に var または非 lazy val がない場合に限ります。これは、怠惰な val が変数よりもメソッドのように機能することを考えると、一種の直感的であり、REPL の 2 つの簡単な例を見ていきます。

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

scala> o.a
res1: Int = 6

この最初の例では、Scala はaを呼び出すことで評価しb、次に を呼び出し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

参照: Scala 2.10 では遅延 val クラス変数はどのように実装されていますか?

于 2013-08-02T06:26:49.553 に答える
2

Java と同様に、クラス インスタンス変数 (または scala val) は、宣言されている場所に関係なく、それを含むクラス/オブジェクトの任意の部分内で「スコープ内」にあります。

とはいえ、それを参照し、宣言のポイントの前に実行されているコードについては、「初期化」されません。lazy-val のコードは、宣言された時点では実行されないため、安全です。

于 2013-08-02T05:23:50.163 に答える