जवाबों:
उनके बीच का अंतर यह है, कि ए val
को तब परिभाषित किया जाता है जब इसे परिभाषित किया जाता है जबकि ए lazy val
को तब निष्पादित किया जाता है जब इसे पहली बार एक्सेस किया जाता है।
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
एक विधि के विपरीत (परिभाषित def
) एक lazy val
बार निष्पादित होता है और फिर कभी नहीं। यह तब उपयोगी हो सकता है जब किसी ऑपरेशन को पूरा होने में लंबा समय लगता है और जब बाद में उपयोग किया जाता है तो यह सुनिश्चित नहीं होता है।
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
यहां, जब मूल्यों x
और y
कभी उपयोग नहीं किया जाता है, तो केवल x
अनावश्यक रूप से संसाधनों को बर्बाद करना। अगर हमें लगता है कि y
इसका कोई साइड इफेक्ट नहीं है और हमें नहीं पता कि यह कितनी बार एक्सेस किया जाता है (कभी नहीं, एक बार, हजारों बार) तो इसे घोषित करना बेकार है def
क्योंकि हम इसे कई बार निष्पादित नहीं करना चाहते हैं।
यदि आप जानना चाहते हैं कि कैसे lazy vals
लागू किया जाता है, तो इस प्रश्न को देखें ।
Lazy<T>
.NET
यह सुविधा न केवल महंगी गणना में देरी करने में मदद करती है, बल्कि पारस्परिक निर्भर या चक्रीय संरचनाओं के निर्माण के लिए भी उपयोगी है। उदाहरण के लिए यह एक ढेर अतिप्रवाह की ओर जाता है:
trait Foo { val foo: Foo }
case class Fee extends Foo { val foo = Faa() }
case class Faa extends Foo { val foo = Fee() }
println(Fee().foo)
//StackOverflowException
लेकिन आलसी वैल के साथ यह ठीक काम करता है
trait Foo { val foo: Foo }
case class Fee extends Foo { lazy val foo = Faa() }
case class Faa extends Foo { lazy val foo = Fee() }
println(Fee().foo)
//Faa()
मैं समझता हूं कि उत्तर दिया गया है, लेकिन मैंने अपने जैसे शुरुआती लोगों के लिए इसे समझना आसान बनाने के लिए एक सरल उदाहरण लिखा है:
var x = { println("x"); 15 }
lazy val y = { println("y"); x+1 }
println("-----")
x = 17
println("y is: " + y)
उपरोक्त कोड का आउटपुट है:
x
-----
y
y is: 18
जैसा कि देखा जा सकता है, जब इसे इनिशियलाइज़ किया जाता है तो x प्रिंट किया जाता है, लेकिन y तब प्रिंट नहीं किया जाता है जब इसे उसी तरीके से इनिशियलाइज़ किया जाता है (मैंने एक्स को जानबूझकर यहाँ लिया है - यह समझाने के लिए कि y इनिशियलाइज़ हो जाता है)। इसके बाद जब y कहा जाता है, तो इसे प्रारंभिक रूप में और साथ ही अंतिम 'x' के मूल्य को ध्यान में रखा जाता है, लेकिन पुराने को नहीं।
उम्मीद है की यह मदद करेगा।
एक आलसी घाटी को सबसे आसानी से " ज्ञापन ( अर्ग ) नहीं " के रूप में समझा जाता है ।
एक बचाव की तरह, एक आलसी घाटी का मूल्यांकन तब तक नहीं किया जाता है जब तक कि इसे लागू नहीं किया जाता है। लेकिन परिणाम सहेजा जाता है ताकि बाद में किए गए इनवॉइस सहेजे गए मान को वापस करें। ज्ञापन परिणाम आपके डेटा संरचना में एक घाटी की तरह जगह लेता है।
जैसा कि दूसरों ने उल्लेख किया है, एक आलसी घाटी के लिए उपयोग के मामले महंगी संगणनाओं को टालने के लिए होते हैं, जब तक उन्हें ज़रूरत होती है और अपने परिणामों को संग्रहीत करते हैं, और मूल्यों के बीच कुछ परिपत्र निर्भरता को हल करने के लिए।
आलसी वैल्स वास्तव में याद दोष के रूप में कम या ज्यादा कार्यान्वित होते हैं। आप उनके कार्यान्वयन के विवरण के बारे में यहां पढ़ सकते हैं:
http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html
lazy
निम्न कोड के अनुसार चक्रीय निर्भरता के बिना भी उपयोगी है:
abstract class X {
val x: String
println ("x is "+x.length)
}
object Y extends X { val x = "Hello" }
Y
एक्सेस Y
करना अब शून्य पॉइंटर अपवाद को फेंक देगा, क्योंकि x
अभी तक इनिशियलाइज़ नहीं किया गया है। हालांकि, निम्नलिखित ठीक काम करता है:
abstract class X {
val x: String
println ("x is "+x.length)
}
object Y extends X { lazy val x = "Hello" }
Y
संपादित करें: निम्नलिखित भी काम करेगा:
object Y extends { val x = "Hello" } with X
इसे "प्रारंभिक आरंभीकरण" कहा जाता है। देखें इस तो सवाल यह अधिक जानकारी के लिए।
का एक प्रदर्शन lazy
- जैसा कि ऊपर बताया गया है - निष्पादन जब परिभाषित बनाम निष्पादन जब एक्सेस किया जाता है: (2.12.7 स्केला शेल का उपयोग करके)
// compiler says this is ok when it is lazy
scala> lazy val t: Int = t
t: Int = <lazy>
//however when executed, t recursively calls itself, and causes a StackOverflowError
scala> t
java.lang.StackOverflowError
...
// when the t is initialized to itself un-lazily, the compiler warns you of the recursive call
scala> val t: Int = t
<console>:12: warning: value t does nothing other than call itself recursively
val t: Int = t
scala> lazy val lazyEight = {
| println("I am lazy !")
| 8
| }
lazyEight: Int = <lazy>
scala> lazyEight
I am lazy !
res1: Int = 8