स्कैला में डीईएफ़, वैल और वर का उपयोग


158
class Person(val name:String,var age:Int )
def person = new Person("Kumar",12)
person.age = 20
println(person.age)

कोड आउटपुट की ये लाइनें 12, भले ही person.age=20सफलतापूर्वक निष्पादित की गई थीं। मैंने पाया कि ऐसा इसलिए होता है क्योंकि मैंने डीफ़ का इस्तेमाल किया है def person = new Person("Kumar",12)। अगर मैं var या Val का उपयोग करता हूं तो आउटपुट है 20। मैं समझता हूं कि डिफ़ॉल्ट स्कैला में वैल है। यह:

def age = 30
age = 45

... एक संकलन त्रुटि देता है क्योंकि यह डिफ़ॉल्ट रूप से एक घाटी है। उपरोक्त लाइनों का पहला सेट ठीक से काम क्यों नहीं करता है, और फिर भी त्रुटि नहीं है?

जवाबों:


254

स्केल में चीजों को परिभाषित करने के तीन तरीके हैं:

  • defएक विधि को परिभाषित करता है
  • valएक निश्चित मान को परिभाषित करता है (जिसे संशोधित नहीं किया जा सकता)
  • varएक चर को परिभाषित करता है (जिसे संशोधित किया जा सकता है)

आपके कोड को देखकर:

def person = new Person("Kumar",12)

यह नामक एक नई विधि को परिभाषित करता है person। आप इस विधि को केवल बिना कॉल कर सकते हैं ()क्योंकि इसे पैरामीटर रहित विधि के रूप में परिभाषित किया गया है। खाली-पेरेन विधि के लिए, आप इसे 'या' के साथ या बिना '' कह सकते हैं। यदि आप बस लिखते हैं:

person

तब आप इस पद्धति को कॉल कर रहे हैं (और यदि आप रिटर्न मान निर्दिष्ट नहीं करते हैं, तो इसे छोड़ दिया जाएगा)। कोड की इस पंक्ति में:

person.age = 20

क्या होता है कि आप पहले personविधि को कॉल करते हैं , और वापसी मूल्य (वर्ग का एक उदाहरण Person) पर आप ageसदस्य चर को बदल रहे हैं ।

और अंतिम पंक्ति:

println(person.age)

यहां आप फिर से personविधि को बुला रहे हैं , जो कक्षा का एक नया उदाहरण देता है Person( ageसेट के साथ 12)। यह इस प्रकार है:

println(person().age)

27
चीजों को भ्रमित करने के लिए, एक की आंतरिक स्थिति को valबदला जा सकता है, लेकिन एक घाटी द्वारा निर्दिष्ट वस्तु नहीं हो सकती है। A valस्थिर नहीं है।
२४:१४

5
चीजों को और अधिक भ्रमित करने के लिए, वैल (और शायद var के रूप में अच्छी तरह से, मैंने कोशिश नहीं की है) एक फ़ंक्शन को परिभाषित करने के लिए इस्तेमाल किया जा सकता है। किसी फ़ंक्शन / पद्धति को परिभाषित करने के लिए डिफ का उपयोग करते समय डीफ़ के शरीर का मूल्यांकन हर बार किया जाता है जिसे यह कहा जाता है। वैल का उपयोग करते समय इसका मूल्यांकन केवल परिभाषा के बिंदु पर किया जाता है। देखें stackoverflow.com/questions/18887264/…
melston

1
@melston हां, लेकिन एक विधि और एक फ़ंक्शन भी बिल्कुल समान नहीं हैं ।
जेस्पर

3
चीजों को और अधिक भ्रमित करने के लिए, डिफ का उपयोग किसी वर्ग के सदस्य चर को परिभाषित करने के लिए भी किया जा सकता है, जरूरी नहीं कि संस्करण का उपयोग करने के लिए।
पेईटी ली

2
@pferrel वास्तव में भ्रमित नहीं है। जावा के फाइनल के साथ भी। आप एक के Listरूप में चिह्नित कर सकते हैं final, लेकिन इसकी सामग्री को संशोधित कर सकते हैं।
jFrenetic

100

मैं डिफाल्ट द्वारा शुरू करूँगा जो कि Scala में def , val और var के बीच मौजूद है ।

  • def - दाईं ओर की सामग्री के लिए एक अपरिवर्तनीय लेबल को परिभाषित करता है जिसे आलसी रूप से मूल्यांकन किया जाता है - नाम से मूल्यांकन।

  • वैल - सही पक्ष की सामग्री के लिए एक अपरिवर्तनीय लेबल को परिभाषित करता है जो कि उत्सुकता से / तुरंत मूल्यांकन किया जाता है - मूल्य द्वारा मूल्यांकन किया जाता है।

  • var - एक परिवर्तनशील चर को परिभाषित करता है , शुरू में मूल्यांकन किए गए राइट साइड कंटेंट पर सेट होता है।

उदाहरण, def

scala> def something = 2 + 3 * 4 
something: Int
scala> something  // now it's evaluated, lazily upon usage
res30: Int = 14

उदाहरण, वैल

scala> val somethingelse = 2 + 3 * 5 // it's evaluated, eagerly upon definition
somethingelse: Int = 17

उदाहरण, var

scala> var aVariable = 2 * 3
aVariable: Int = 6

scala> aVariable = 5
aVariable: Int = 5

ऊपर के अनुसार, डीईएफ और वैल से लेबल को पुन: असाइन नहीं किया जा सकता है, और किसी भी प्रयास के मामले में नीचे की तरह एक त्रुटि होगी:

scala> something = 5 * 6
<console>:8: error: value something_= is not a member of object $iw
       something = 5 * 6
       ^

जब वर्ग को परिभाषित किया जाता है:

scala> class Person(val name: String, var age: Int)
defined class Person

और फिर के साथ त्वरित:

scala> def personA = new Person("Tim", 25)
personA: Person

व्यक्ति के उस विशिष्ट उदाहरण (अर्थात 'व्यक्तित्व') के लिए एक अपरिवर्तनीय लेबल बनाया जाता है। जब भी परिवर्तनशील क्षेत्र 'आयु' को संशोधित करने की आवश्यकता होती है, तो ऐसा प्रयास विफल हो जाता है:

scala> personA.age = 44
personA.age: Int = 25

जैसी कि उम्मीद थी, 'उम्र' एक गैर-परस्पर लेबल का हिस्सा है। इस पर काम करने का सही तरीका एक परिवर्तनशील चर का उपयोग करना है, जैसे निम्नलिखित उदाहरण में:

scala> var personB = new Person("Matt", 36)
personB: Person = Person@59cd11fe

scala> personB.age = 44
personB.age: Int = 44    // value re-assigned, as expected

स्पष्ट रूप से, परिवर्तनशील परिवर्तनीय संदर्भ (अर्थात 'personB') से वर्ग उत्परिवर्तित क्षेत्र 'आयु' को संशोधित करना संभव है।

मैं अब भी इस तथ्य पर जोर दूंगा कि उपर्युक्त अंतर से सब कुछ आता है, किसी भी स्काला प्रोग्रामर के दिमाग में स्पष्ट होना चाहिए।


मुझे नहीं लगता कि उपरोक्त स्पष्टीकरण सही है। अन्य उत्तर देखें।
प्रति मिल्डनर

@PerMildner क्या आप इस बारे में विस्तार से बता सकते हैं कि उपरोक्त उत्तर में क्या गलत है?
सैयद सुबन

मुझे याद नहीं है कि मेरी मूल शिकायत क्या थी। हालांकि, उत्तर का अंतिम भाग, personAएट अल के बारे में । बंद लगता है। चाहे ageआप उपयोग करते हैं def personAया नहीं , सदस्य कार्य को संशोधित करता है या नहीं var personB। अंतर यह है कि जिस def personAमामले में आप संशोधन कर रहे हैं, Personवह आपके पहले मूल्यांकन से लौटा हुआ है personA। यह उदाहरण है संशोधित है, लेकिन यह है जब आप एक बार फिर से मूल्यांकन क्या दिया जाता है नहीं है personA। इसके बजाय, दूसरी बार जब आप करते personA.ageहैं तो आप प्रभावी रूप से कर रहे हैं new Person("Tim",25).age
प्रति Mildner

29

साथ में

def person = new Person("Kumar", 12) 

आप एक फ़ंक्शन / आलसी चर को परिभाषित कर रहे हैं जो हमेशा "कुमार" और उम्र 12. नाम के साथ एक नया व्यक्ति उदाहरण देता है। यह पूरी तरह से वैध है और कंपाइलर के पास शिकायत करने का कोई कारण नहीं है। कॉलिंग person.age इस नए बनाए गए व्यक्ति उदाहरण की आयु वापस कर देगा, जो हमेशा 12 है।

लिखते समय

person.age = 45

आप वर्ग व्यक्ति में उम्र की संपत्ति के लिए एक नया मूल्य प्रदान करते हैं, जो कि उम्र के रूप में घोषित होने के बाद से मान्य है var। यदि आप personकिसी नए व्यक्ति ऑब्जेक्ट के साथ पुन: असाइन करने का प्रयास करते हैं तो कंपाइलर शिकायत करेगा

person = new Person("Steve", 13)  // Error

हाँ। इस बिंदु को व्यक्ति पर हैशकोड
नीलांजन सरकार

26

एक और परिप्रेक्ष्य प्रदान करने के लिए, स्काला में "डीफ़" का मतलब है कि हर बार जब इसका उपयोग किया जाता है, तो मूल्यांकन किया जाएगा, जबकि वैल एक ऐसी चीज़ है जिसका मूल्यांकन तुरंत और केवल एक बार किया जाता है । यहां, अभिव्यक्ति में def person = new Person("Kumar",12)जोर दिया गया है कि जब भी हम "व्यक्ति" का उपयोग करते हैं तो हमें new Person("Kumar",12)कॉल मिलेगा । इसलिए यह स्वाभाविक है कि दो "person.age" गैर-संबंधित हैं।

यह वह तरीका है जो मैं स्काला को समझता हूं (शायद अधिक "कार्यात्मक" तरीके से)। मुझे यकीन नहीं है अगर

def defines a method
val defines a fixed value (which cannot be modified)
var defines a variable (which can be modified)

हालांकि वास्तव में स्काला का क्या मतलब है। मैं वास्तव में कम से कम इस तरह से सोचना पसंद नहीं करता ...


20

जैसा कि किंटारो पहले से ही कहता है, व्यक्ति एक विधि है (डीफ़ के कारण) और हमेशा एक नया व्यक्ति उदाहरण देता है। जैसा कि आपको पता चला है कि अगर आप विधि को var या val में बदलते हैं तो यह काम करेगा:

val person = new Person("Kumar",12)

एक और संभावना होगी:

def person = new Person("Kumar",12)
val p = person
p.age=20
println(p.age)

हालाँकि, person.age=20आपके कोड में अनुमति दी गई है, क्योंकि आपको विधि Personसे एक उदाहरण मिलता है person, और इस उदाहरण पर आपको a का मान बदलने की अनुमति है var। समस्या यह है, कि उस पंक्ति के बाद आपके पास उस उदाहरण का कोई और संदर्भ नहीं है (जैसा कि हर कॉल personएक नया उदाहरण प्रस्तुत करेगा)।

यह कुछ खास नहीं है, आप जावा में बिल्कुल वैसा ही व्यवहार करेंगे:

class Person{ 
   public int age; 
   private String name;
   public Person(String name; int age) {
      this.name = name;  
      this.age = age;
   }
   public String name(){ return name; }
}

public Person person() { 
  return new Person("Kumar", 12); 
}

person().age = 20;
System.out.println(person().age); //--> 12

8

आइए इसे लेते हैं:

class Person(val name:String,var age:Int )
def person =new Person("Kumar",12)
person.age=20
println(person.age)

और समान कोड के साथ इसे फिर से लिखना

class Person(val name:String,var age:Int )
def person =new Person("Kumar",12)
(new Person("Kumar", 12)).age_=(20)
println((new Person("Kumar", 12)).age)

देखें, defएक विधि है। यह कहा जाता है कि हर बार निष्पादित करेगा, और हर बार यह (ए) वापस आ जाएगा new Person("Kumar", 12)। और ये "असाइनमेंट" में कोई त्रुटि नहीं है क्योंकि यह वास्तव में असाइनमेंट नहीं है, लेकिन केवल age_=विधि के लिए एक कॉल है (द्वारा प्रदान की गई है var)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.