2013-07-14 9 views
5

クラス変数の場合lazy valの実装について質問するquestionがあります。Scalaのローカル遅延型変数はどのように実装されていますか?

def foo[A](a: => A) = { 
    lazy val x: A = a 
    // return something that uses x 
} 
+0

ロジックは同じですが、同期は必要ありません。 –

+0

@RandallSchulzしかし、[x]がスコープをエスケープすると、[ここ](https://github.com/scalaz/scalaz/blob/59bdfecdae88f8e166f8d39cd08879ed87f3db17/core/src/main/scala/scalaz/Name.scala#L39 )?その後、複数のスレッドからアクセスできます。 –

+0

うーん...はい!その場合、明らかに同期が必要となります。 –

答えて

3

ローカル変数、そのように実装されているどのようにそれは方法で怠惰なヴァルスを使用するために少し小さいが効率的です。その理由は、実際には関数をネストすることができないので、スタックに名目上割り当てられた遅延ビットが実際にヒープ上に移動する必要があるからです。したがって、少なくとも1つの余分なオブジェクトを作成しなければならず、Scalaが実際に2つを作成することが分かります。

class Baz{ 
    def baz(i: => Int, b: Boolean) = { 
    lazy val j = i 
    if (b) j else 0 
    } 
} 

は、とりわけ

public int baz(scala.Function0, boolean); 
    Code: 
    0: new #12; //class scala/runtime/IntRef 
    3: dup 
    4: iconst_0 
    5: invokespecial #16; //Method scala/runtime/IntRef."<init>":(I)V 
    8: astore_3 
    9: new #18; //class scala/runtime/VolatileByteRef 
    12: dup 
    13: iconst_0 
    14: invokespecial #21; //Method scala/runtime/VolatileByteRef."<init>":(B)V 
    17: astore 4 
    19: iload_2 
    20: ifeq 34 
    23: aload_0 
    24: aload_1 
    25: aload_3 
    26: aload 4 
    28: invokespecial #25; //Method j$1:(Lscala/Function0;Lscala/runtime/IntRef; 
               Lscala/runtime/VolatileByteRef;)I 
    31: goto 35 
    34: iconst_0 
    35: ireturn 

IntRefVolatileByteRefの作成を参照してください?、変身しますかこれらは通常、怠惰なヴァルを扱うためのプライベートバールの代わりになります。そして今やj$1は、遅延ロードの検索や作成を処理するために作成されたアクセサメソッドで、新たに作成された2つのクラスをパラメータ(by-name関数に加えて)として扱わなければなりません。

基本的な仕組みは同じですが、実装の詳細が異なり、varsをスティックする別のクラスが既にある場合よりも効率が悪いです。

関連する問題