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.
Die Logik ist die gleiche, aber keine Synchronisation erforderlich. –
@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. –
Hmmm ... Ja! In diesem Fall wäre eine klare Synchronisation erforderlich. –