2012-02-08 17 views
3
case class Test(kind: Int) { 
    val ifX = if (isX) "is X" else "not X" 
    val isX = kind == 1 
} 

val test = Test(1) 
println("ifX=%s, isX=%b".format(test.ifX, test.isX)) 

なぜこのコード印刷: ifXを=ではないX、ISX =真奇妙な行動

移動 "ヴァルifXを" は "ifXを" の前にあるとき、それは大丈夫です(印刷ifXを=がXである)

編集:私はそれを修正する方法を知っています。この状況でコンパイラが警告またはエラーを出さない理由を理解できません。

+3

スカラーについて何も知らないのなら、ifXがisXの前に初期化されていると思います。宣言の順序を逆にしてみてください。 –

答えて

7

あなたはスカラーで順序は関係ないと仮定しています。します。 isXはの変数の値であり、ifXが実行されたときに定義されていますが、値はまだ初期化されていないため、型のデフォルト(boolean、false)です。

isXを関数(def isX = ...)として再定義するとうまくいきます。

これは、次のJavaとほぼ同等です:

class Test { 
    String ifX; 
    bool isX; // Defaults to false, its a primitive after all 
    public Test(Int kind) { 
     ifX = isX ? "is X" : "not X"; 
     isX = kind == 1; 
    } 
} 
+0

"ifX"が "ifX"でユニット化されていて、コンパイラからの警告またはエラーが表示されないのはなぜですか?なぜコンパイラは定義されていないと思いますか?==デフォルト値です。これは私にとっては奇妙です。エラーが発生する可能性があります。 –

+0

Scalaは鋭いツールです。私が言うことができるのは、 "注意してください"です。 http://codebetter.com/jefferypalermo/2007/12/02/who-is-to-say-that-my-knife-is-too-sharp-for-my-own-good/ –

+0

ページをポイントできますかこの動作が定義されている "Scala Reference"?私は見ているが、これを見つけることができません:/ –

1

クラスが最初に実行されたときに、ISXは未定義です。 両方の回線を切り替えることはできますか?

7

Chris Shainが指摘しているように、isXはまだ定義されていません。変数ではなく、の値がであるということを追加したいだけです。つまり、実際に怠け者にすることができます。遅延値は、必要なときにのみインスタンス化されます。 ifXisXの両方を理論的に怠け者にすることができます。

case class Test(kind: Int) { 
    val ifX = if (isX) "is X" else "not X" 
    lazy val isX = kind == 1 
} 

希望の出力が得られるはずです。

7

OMG、私はそれが静的に誤っ指数時間よりももっと良いものにすべての場合に前方参照を使用し検出することはできません

...私たちは、この通過行くよ何回だろう。そうであれば誰もそれをやっていないほど複雑です。

この特殊なケースは継承がなく、特性が拡張されず、初期イニシャライザが初期化されず、メソッドが呼び出されず、クロージャも機能もなく、何もありません。将来的には警告が追加されるほど簡単です。

実行時にキャッチすることができ、Scalaはそのために-Xcheckinitフラグを提供します。

ちなみに、Javaでまったく同じ問題が発生することがありますが、で警告します。特別な場合です。

+0

+1の '-Xcheckinit' – leedm777