2013-07-14 5 views
5

Es gibt eine question Frage über die Implementierung von lazy val s, wenn sie Klassenvariablen sind. Wie lokale Variablen, wie inWie werden die lokalen Lazy-Variablen von Scala implementiert?

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

Die Logik ist die gleiche, aber keine Synchronisation erforderlich. –

+0

@RandallSchulz Aber was, wenn 'x' seinen Geltungsbereich verlässt, wie in [hier] (https://github.com/scalaz/scalaz/blob/59bdfecdae88f8e166f8d39cd08879ed87f3db17/core/src/main/scala/scalaz/Name.scala#L39) Dann kann auf mehrere Threads zugegriffen werden. –

+0

Hmmm ... Ja! In diesem Fall wäre eine klare Synchronisation erforderlich. –

Antwort

3

Es ist ein bisschen weniger effizient zu nutzen faul vals in einem Verfahren durchgeführt werden. Der Grund ist, dass Sie Funktionen nicht verschachteln können, so dass die Lazy-Bits, die nominell auf dem Stack zugewiesen sind, tatsächlich auf den Heap gehen müssen. Sie müssen also mindestens ein zusätzliches Objekt erstellen, und es stellt sich heraus, dass Scala tatsächlich zwei Objekte erstellt.

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

verwandelt sich in unter anderem

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 

die Schaffung von IntRef und VolatileByteRef sehen? Diese sind anstelle von dem, was normalerweise nur private vars sein würde, um das faule val zu behandeln. Und jetzt j$1, muss die Accessor-Methode, die zum Abrufen und/oder Erstellen des Lazy Val erstellt wurde, diese beiden neu erstellten Klassen als Parameter verwenden (zusätzlich zur By-Name-Funktion).

Also während die zugrundeliegenden Mechanismen die gleichen sind, sind die Implementierungsdetails anders und weniger effizient als wenn Sie bereits eine andere Klasse um die Vars haben.