La différence entre eux est que a val
est exécuté quand il est défini tandis que a lazy val
est exécuté quand on y accède la première fois.
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
Contrairement à une méthode (définie par def
), a lazy val
est exécuté une fois, puis plus jamais. Cela peut être utile lorsqu'une opération prend du temps à se terminer et lorsqu'il n'est pas sûr qu'elle soit utilisée ultérieurement.
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
Ici, lorsque les valeurs x
et y
ne sont jamais utilisées, ne font que x
gaspiller inutilement des ressources. Si nous supposons que cela y
n'a pas d'effets secondaires et que nous ne savons pas à quelle fréquence il est consulté (jamais, une fois, des milliers de fois), il est inutile de le déclarer def
car nous ne voulons pas l'exécuter plusieurs fois.
Si vous voulez savoir comment lazy vals
sont mis en œuvre, consultez cette question .
Lazy<T>
.NETCette fonctionnalité permet non seulement de retarder des calculs coûteux, mais est également utile pour construire des structures mutuellement dépendantes ou cycliques. Par exemple, cela entraîne un débordement de pile:
Mais avec des vals paresseux, cela fonctionne bien
la source
Je comprends que la réponse est donnée mais j'ai écrit un exemple simple pour le rendre facile à comprendre pour les débutants comme moi:
La sortie du code ci-dessus est:
Comme on peut le voir, x est imprimé quand il est initialisé, mais y n'est pas imprimé quand il est initialisé de la même manière (j'ai pris x comme var intentionnellement ici - pour expliquer quand y est initialisé). Ensuite, lorsque y est appelé, il est initialisé ainsi que la valeur du dernier «x» est pris en considération, mais pas l'ancien.
J'espère que cela t'aides.
la source
Un val paresseux est plus facilement compris comme un " def mémorisé (sans argument)".
Comme un def, un val paresseux n'est évalué que lorsqu'il est invoqué. Mais le résultat est enregistré de sorte que les invocations suivantes renvoient la valeur enregistrée. Le résultat mémorisé prend de la place dans votre structure de données, comme un val.
Comme d'autres l'ont mentionné, les cas d'utilisation d'un val paresseux sont de différer les calculs coûteux jusqu'à ce qu'ils soient nécessaires et de stocker leurs résultats, et de résoudre certaines dépendances circulaires entre les valeurs.
Les valeurs paresseuses sont en fait implémentées plus ou moins comme des définitions mémorisées. Vous pouvez lire les détails de leur mise en œuvre ici:
http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html
la source
Est également
lazy
utile sans dépendances cycliques, comme dans le code suivant:L'accès lèvera
Y
désormais une exception de pointeur nul, car ilx
n'est pas encore initialisé. Cependant, ce qui suit fonctionne bien:EDIT: les éléments suivants fonctionneront également:
C'est ce qu'on appelle un "initialiseur précoce". Voir cette question SO pour plus de détails.
la source
Une démonstration
lazy
- comme défini ci-dessus - de l'exécution lorsqu'elle est définie par rapport à l'exécution lors de l'accès: (en utilisant le shell scala 2.12.7)la source
la source