Der Unterschied zwischen ihnen besteht darin, dass a val
ausgeführt wird, wenn es definiert ist, während a lazy val
ausgeführt wird, wenn beim ersten Zugriff darauf zugegriffen wird.
scala> val x = { println("x"); 15 }
x
x: Int = 15
scala> lazy val y = { println("y"); 13 }
y: Int = <lazy>
scala> x
res2: Int = 15
scala> y
y
res3: Int = 13
scala> y
res4: Int = 13
Im Gegensatz zu einer Methode (definiert mit def
) lazy val
wird a einmal und dann nie wieder ausgeführt. Dies kann nützlich sein, wenn ein Vorgang lange dauert und nicht sicher ist, ob er später verwendet wird.
scala> class X { val x = { Thread.sleep(2000); 15 } }
defined class X
scala> class Y { lazy val y = { Thread.sleep(2000); 13 } }
defined class Y
scala> new X
res5: X = X@262505b7 // we have to wait two seconds to the result
scala> new Y
res6: Y = Y@1555bd22 // this appears immediately
Hier werden, wenn die Werte x
und y
nie verwendet werden, nur x
unnötig Ressourcen verschwendet. Wenn wir annehmen, dass dies y
keine Nebenwirkungen hat und wir nicht wissen, wie oft darauf zugegriffen wird (niemals, einmal, tausende Male), ist es sinnlos, dies als zu deklarieren, def
da wir es nicht mehrmals ausführen möchten.
Wenn Sie wissen möchten, wie sie lazy vals
implementiert werden, lesen Sie diese Frage .
Lazy<T>
in .NETDiese Funktion verzögert nicht nur teure Berechnungen, sondern ist auch nützlich, um voneinander abhängige oder zyklische Strukturen aufzubauen. Dies führt beispielsweise zu einem Stapelüberlauf:
Aber mit faulen Vals funktioniert es gut
quelle
Ich verstehe, dass die Antwort gegeben ist, aber ich habe ein einfaches Beispiel geschrieben, um Anfängern wie mir das Verständnis zu erleichtern:
Die Ausgabe des obigen Codes ist:
Wie zu sehen ist, wird x gedruckt, wenn es initialisiert wird, aber y wird nicht gedruckt, wenn es auf die gleiche Weise initialisiert wird (ich habe x hier absichtlich als var genommen - um zu erklären, wann y initialisiert wird). Wenn y als nächstes aufgerufen wird, wird es initialisiert und der Wert des letzten 'x' wird berücksichtigt, aber nicht der alte.
Hoffe das hilft.
quelle
Ein fauler Wert wird am leichtesten als " auswendig gelernt (no-arg) def" verstanden.
Wie ein Def wird ein Lazy Val erst ausgewertet, wenn er aufgerufen wird. Das Ergebnis wird jedoch gespeichert, sodass nachfolgende Aufrufe den gespeicherten Wert zurückgeben. Das gespeicherte Ergebnis nimmt wie ein Wert Platz in Ihrer Datenstruktur ein.
Wie andere erwähnt haben, bestehen die Anwendungsfälle für einen Lazy Val darin, teure Berechnungen aufzuschieben, bis sie benötigt werden, und ihre Ergebnisse zu speichern und bestimmte zirkuläre Abhängigkeiten zwischen Werten zu lösen.
Lazy Vals werden in der Tat mehr oder weniger als gespeicherte Defs implementiert. Details zur Implementierung finden Sie hier:
http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html
quelle
Auch
lazy
ist nützlich , ohne zyklische Abhängigkeiten, wie im folgenden Code:Beim Zugriff
Y
wird jetzt eine Nullzeigerausnahme ausgelöst, da diesex
noch nicht initialisiert ist. Folgendes funktioniert jedoch einwandfrei:BEARBEITEN: Folgendes wird auch funktionieren:
Dies wird als "früher Initialisierer" bezeichnet. Weitere Informationen finden Sie in dieser SO-Frage .
quelle
Eine Demonstration der
lazy
- wie oben definierten - Ausführung bei Definition im Vergleich zur Ausführung beim Zugriff: (unter Verwendung der 2.12.7-Scala-Shell)quelle
quelle