To nieco mniej wydajny w użyciu leniwe Vals w metodzie. Powodem jest to, że nie można faktycznie zagnieżdżać funkcji, więc leniwe bity, które nominalnie są przydzielane na stosie, rzeczywiście muszą przejść na ster. Musisz więc stworzyć co najmniej jeden dodatkowy obiekt i okazuje się, że Scala faktycznie tworzy dwa.
class Baz{
def baz(i: => Int, b: Boolean) = {
lazy val j = i
if (b) j else 0
}
}
zamienia się między innymi
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
Zobacz tworzenie IntRef
i VolatileByteRef
? Są na miejscu tego, co normalnie byłoby po prostu prywatnymi varami, aby poradzić sobie z leniwym valem. A teraz j$1
, metoda accessor utworzona do obsługi pobierania i/lub tworzenia leniwego val, musi przyjąć te dwie nowo utworzone klasy jako parametry (oprócz funkcji nazwy).
Tak więc, podczas gdy podstawowa mechanika jest taka sama, szczegóły implementacji są inne i mniej wydajne, niż gdybyś miał już inną klasę, w której można trzymać znaki.
Logika jest taka sama, ale synchronizacja nie jest wymagana. –
@RandallSchulz Ale co jeśli 'x' wymyka się jego zakresowi, jak w [tutaj] (https://github.com/scalaz/scalaz/blob/59bdfecdae88f8e166f8d39cd08879ed87f3db17/core/src/main/scala/scalaz/Name.scala#L39)? Dostęp do niego można uzyskać dzięki wielu wątkom. –
Hmmm ... Tak! W takim przypadku wymagana byłaby wyraźna synchronizacja. –