2012-03-31 8 views
10

なぜコードブロック内で変数を再帰的に定義できないのですか?なぜコードブロック内で変数を再帰的に定義できないのですか?

scala> { 
    | val test: Stream[Int] = 1 #:: test 
    | } 
<console>:9: error: forward reference extends over definition of value test 
       val test: Stream[Int] = 1 #:: test 
              ^

scala> val test: Stream[Int] = 1 #:: test 
test: Stream[Int] = Stream(1, ?) 

lazyキーワードは、この問題を解決するが、それは、コードブロックせずに動作しますが、コードブロックにコンパイルエラーがスローされますなぜ私が理解することはできません。

答えて

23

注多かれ少なかれ次のようにだから

object REPL$1 { 
    val something = "a value" 
} 
import REPL$1._ 

、任意val(又はdef、など)が内部REPLヘルパーオブジェクトのメンバーであります。これは、ブロック内val Sには当てはまりません

object ForwardTest { 
    def x = y // val x would also compile but with a more confusing result 
    val y = 2 
} 
ForwardTest.x == 2 

今の点は、クラス(およびオブジェクト)がそのメンバーの前方参照ができていることです。ブロックでは、すべてが線形の順序で定義されなければなりません。したがって、valはメンバーではなく、単純な変数(または値)です。次のいずれもコンパイルされません。

def plainMethod = { // could as well be a simple block 
    def x = y 
    val y = 2 
    x 
} 

<console>: error: forward reference extends over definition of value y 
    def x = y 
      ^

違いを生む再帰ではありません。違いは、クラスとオブジェクトは前方参照を許可しますが、ブロックは許可しません。

object O { 
    val x = y 
    val y = 0 
} 

をあなたが実際にこれを書いている:私はあなたが書いたときにすることを追加します

2

この動作の理由は、さまざまなvalの初期化時間によって異なります。 val x = 5をREPLに直接入力すると、xはオブジェクトのメンバーになります。この値はデフォルト値(null、0、0.0、false)で初期化できます。対照的に、ブロック内の値はデフォルト値では初期化できません。

これは異なる動作になる傾向:Scalaの2.10最後の例では

scala> class X { val x = y+1; val y = 10 } 
defined class X 

scala> (new X).x 
res17: Int = 1 

scala> { val x = y+1; val y = 10; x } // compiles only with 2.9.0 
res20: Int = 11 

はもうコンパイルされません。 2.9.0では、値はコンパイラによって並べ替えられてコンパイルされます。さまざまな初期化時間を記述するbug reportがあります。 REPLに

scala> val something = "a value" 

が評価されること

+0

最後の例はコンパイルされません。 (どちらが問題なのでしょうか) – Debilski

+0

@Debilski:あなたは正しいですが、2.10ではもうコンパイルされません。私はバグレポートで述べたようにこれをコンパイルするために2.9.0を使用しました。 – sschaef

+0

私は2.9.1-1を使用していました。だからそれは間に変更されているに違いない。 – Debilski

4

object O { 
    val x = this.y 
    val y = 0 
} 

少しthisは、あなたが定義の中このようなものを宣言するときに欠けているものであること。

0

EclipseベースのScala-IDE(v4.0.0)のScalaワークシートがREPLのように振る舞いません(例えば、https://github.com/scala-ide/scala-worksheet/wiki/Getting-Startedは「ワークシートはステロイドのREPLセッションのようです")という点ではなく、1つの長いメソッドの定義に似ています。つまり、ワークシート内のval定義(再帰的val定義を含む)を前方参照することは、オブジェクトまたはクラスのメンバーにする必要があります。

関連する問題