खोज…


टिप्पणियों

के रूप में val शब्दार्थ स्थिर हैं, वे "यथा-स्थान" प्रारंभ कर रहे हैं चाहे वे कहीं भी कोड में दिखाई देते हैं। अमूर्त वर्गों और लक्षणों में उपयोग किए जाने पर यह आश्चर्यजनक और अवांछनीय व्यवहार पैदा कर सकता है।

उदाहरण के लिए, PlusOne लें कि हम PlusOne नामक एक विशेषता बनाना चाहते हैं जो एक लिपटे Int पर एक वृद्धि ऑपरेशन को परिभाषित करता है। चूंकि Int एस अपरिवर्तनीय हैं, इसलिए मूल्य प्लस एक को आरंभीकरण पर जाना जाता है और बाद में इसे कभी नहीं बदला जाएगा, इसलिए शब्दार्थ यह एक val । हालांकि, इसे इस तरह परिभाषित करने से अप्रत्याशित परिणाम प्राप्त होगा।

trait PlusOne {
    val i:Int

    val incr = i + 1
}

class IntWrapper(val i: Int) extends PlusOne

कोई फर्क नहीं पड़ता मूल्य i आप का निर्माण IntWrapper साथ, बुला .incr लौटे वस्तु पर हमेशा वापस आ जाएगी 1. इसका कारण यह है वैल है incr विस्तार कक्षा से पहले, विशेषता में आरंभ नहीं हो जाता है, और उस समय i केवल का डिफ़ॉल्ट मान है 0 । (अन्य स्थितियों में, इसे Nil , null या इसी तरह के डिफ़ॉल्ट के साथ आबाद किया जा सकता है।)

सामान्य नियम, फिर, किसी भी मूल्य पर val का उपयोग करने से बचना है जो एक अमूर्त क्षेत्र पर निर्भर करता है। इसके बजाय, lazy val उपयोग करें, जो तब तक मूल्यांकन नहीं करता है जब तक इसकी आवश्यकता नहीं है, या def , जो हर बार मूल्यांकन करने के बाद इसे कहा जाता है। ध्यान दें कि यदि lazy val को आरंभीकरण पूरा होने से पहले एक val द्वारा मूल्यांकन करने के लिए मजबूर किया जाता है, तो वही त्रुटि होगी।

एक फिडेल (स्काला-जेएस में लिखा गया है, लेकिन एक ही व्यवहार लागू होता है) यहां पाया जा सकता है।

वार, वैल और डेफ

वर

एक var एक संदर्भ चर है, जावा जैसी भाषाओं में चर के समान है। विभिन्न वस्तुओं को एक var स्वतंत्र रूप से सौंपा जा सकता है, इसलिए जब तक कि दी गई वस्तु में एक ही प्रकार होता है जो कि var साथ घोषित किया गया था:

scala> var x = 1
x: Int = 1

scala> x = 2
x: Int = 2

scala> x = "foo bar"
<console>:12: error: type mismatch;
 found   : String("foo bar")
 required: Int
       x = "foo bar"
       ^

के प्रकार के ऊपर के उदाहरण में नोट var पहले मान काम दिया संकलक द्वारा अनुमान लगाया गया था।

वैल

एक val एक निरंतर संदर्भ है। इस प्रकार, एक नई वस्तु को एक val को नहीं सौंपा जा सकता है जिसे पहले से ही सौंपा गया है।

scala> val y = 1
y: Int = 1

scala> y = 2
<console>:12: error: reassignment to val
       y = 2
         ^

हालांकि, उद्देश्य यह है कि एक val अंक पर स्थिर नहीं है। उस वस्तु को संशोधित किया जा सकता है:

scala> val arr = new Array[Int](2)
arr: Array[Int] = Array(0, 0)

scala> arr(0) = 1

scala> arr
res1: Array[Int] = Array(1, 0)

डीईएफ़

एक def एक विधि को परिभाषित करता है। एक विधि को फिर से नहीं सौंपा जा सकता है।

scala> def z = 1
z: Int

scala> z = 2
<console>:12: error: value z_= is not a member of object $iw
       z = 2
       ^

उपरोक्त उदाहरणों में, val y और def z समान मान लौटाते हैं। हालांकि, किसी def का मूल्यांकन तब किया जाता है जब इसे कहा जाता है , जबकि किसी val या var का मूल्यांकन तब किया जाता है जब इसे असाइन किया जाता है । इसके परिणामस्वरूप भिन्न व्यवहार हो सकते हैं जब परिभाषा के दुष्प्रभाव होते हैं:

scala> val a = {println("Hi"); 1}
Hi
a: Int = 1

scala> def b = {println("Hi"); 1}
b: Int

scala> a + 1
res2: Int = 2

scala> b + 1
Hi
res3: Int = 2

कार्य

क्योंकि फ़ंक्शन मान हैं, उन्हें val / var / def s में असाइन किया जा सकता है। बाकी सब उसी तरीके से काम करते हैं जैसे ऊपर:

scala> val x = (x: Int) => s"value=$x"
x: Int => String = <function1>

scala> var y = (x: Int) => s"value=$x"
y: Int => String = <function1>

scala> def z = (x: Int) => s"value=$x"
z: Int => String

scala> x(1)
res0: String = value=1

scala> y(2)
res1: String = value=2

scala> z(3)
res2: String = value=3

आलसी घाटी

lazy val एक भाषा की विशेषता है जहां पहली बार पहुंचने तक किसी val के आरंभ में देरी होती है। उस बिंदु के बाद, यह एक नियमित val तरह काम करता है।

इसका उपयोग करने के लिए val से पहले lazy कीवर्ड जोड़ें। उदाहरण के लिए, REPL का उपयोग कर:

scala> lazy val foo = {
     |   println("Initializing")
     |   "my foo value"
     | }
foo: String = <lazy>

scala> val bar = {
     |   println("Initializing bar")
     |   "my bar value"
     | }
Initializing bar
bar: String = my bar value

scala> foo
Initializing
res3: String = my foo value

scala> bar
res4: String = my bar value

scala> foo
res5: String = my foo value

यह उदाहरण निष्पादन आदेश को प्रदर्शित करता है। जब lazy val घोषित किया जाता है, तो वह सब जो foo वैल्यू में सेव होता है, एक आलसी फंक्शन कॉल है, जिसका मूल्यांकन अभी तक नहीं किया गया है। जब नियमित val सेट किया जाता है, तो हम println कॉल निष्पादित करते हैं और मूल्य को bar को सौंपा जाता है। हम evalute जब foo पहली बार हम देखते हैं println पर अमल - लेकिन यह दूसरी बार नहीं मूल्यांकन किया जाता है जब। इसी तरह, जब bar का मूल्यांकन किया जाता है तो हमें println एक्जीक्यूट दिखाई नहीं देता है - केवल जब यह घोषित किया जाता है।

जब 'आलसी' का उपयोग करने के लिए

  1. प्रारंभ कम्प्यूटेशनल रूप से महंगा है और val का उपयोग दुर्लभ है।

    lazy val tiresomeValue = {(1 to 1000000).filter(x => x % 113 == 0).sum}
    if (scala.util.Random.nextInt > 1000) {
      println(tiresomeValue)
    }
    

    tiresomeValue गणना के लिए एक लंबा समय लगता है, और यह हमेशा उपयोग नहीं किया जाता है। इसे lazy val बनाने से अनावश्यक संगणना बचती है।

  2. चक्रीय निर्भरता को हल करना

    आइए एक उदाहरण को दो वस्तुओं के साथ देखें जिन्हें तात्कालिकता के दौरान एक ही समय में घोषित करने की आवश्यकता है:

    object comicBook {
      def main(args:Array[String]): Unit = {
        gotham.hero.talk()
        gotham.villain.talk()
      }
    }
    
    class Superhero(val name: String) {
      lazy val toLockUp = gotham.villain
      def talk(): Unit = {
        println(s"I won't let you win ${toLockUp.name}!")
      }
    }
    
    class Supervillain(val name: String) {
      lazy val toKill = gotham.hero
      def talk(): Unit = {
        println(s"Let me loosen up Gotham a little bit ${toKill.name}!")
      }
    }
    
    object gotham {
      val hero: Superhero = new Superhero("Batman")
      val villain: Supervillain = new Supervillain("Joker")
    }
    

    कीवर्ड के बिना lazy , संबंधित ऑब्जेक्ट किसी ऑब्जेक्ट के सदस्य नहीं हो सकते। इस तरह के कार्यक्रम के निष्पादन से java.lang.NullPointerException परिणाम होगा। lazy का उपयोग करके, संदर्भ को एक आरंभिक मूल्य के डर के बिना, आरंभीकृत होने से पहले सौंपा जा सकता है।

ओवरलोडिंग डिफ

आप एक ओवरलोड कर सकते हैं def यदि हस्ताक्षर अलग है:

def printValue(x: Int) {
  println(s"My value is an integer equal to $x")
}

def printValue(x: String) {
  println(s"My value is a string equal to '$x'")
}

printValue(1)  // prints "My value is an integer equal to 1"
printValue("1") // prints "My value is a string equal to '1'"

यह वही कार्य करता है, जो कक्षाओं, लक्षणों, वस्तुओं या वस्तुओं के अंदर होता है।

नामित पैरामीटर्स

जब कोई def , तो पैरामीटर को नाम से स्पष्ट रूप से असाइन किया जा सकता है। ऐसा करने का मतलब है कि उन्हें सही तरीके से ऑर्डर करने की आवश्यकता नहीं है। उदाहरण के लिए, printUs() को इस printUs() परिभाषित करें:

// print out the three arguments in order.
def printUs(one: String, two: String, three: String) = 
   println(s"$one, $two, $three")

अब इसे इन तरीकों से (दूसरों के बीच) कहा जा सकता है:

printUs("one", "two", "three") 
printUs(one="one", two="two", three="three")
printUs("one", two="two", three="three")
printUs(three="three", one="one", two="two") 

इससे सभी मामलों में one, two, three प्रिंट हो रहे हैं।

यदि सभी तर्कों का नाम नहीं दिया जाता है, तो पहली दलीलें क्रम से मेल खाती हैं। कोई भी स्थितिगत (गैर-नामित) तर्क किसी नामित का अनुसरण नहीं कर सकता है:

printUs("one", two="two", three="three") // prints 'one, two, three'
printUs(two="two", three="three", "one") // fails to compile: 'positional after named argument'


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow