स्काला में परिभाषा varऔर valपरिभाषा के बीच क्या अंतर है और भाषा को दोनों की आवश्यकता क्यों है? आप एक valसे अधिक varऔर इसके विपरीत क्यों चुनेंगे ?
स्काला में परिभाषा varऔर valपरिभाषा के बीच क्या अंतर है और भाषा को दोनों की आवश्यकता क्यों है? आप एक valसे अधिक varऔर इसके विपरीत क्यों चुनेंगे ?
जवाबों:
जैसा कि कई अन्य लोगों ने कहा है, किसी को सौंपी गई वस्तु को valप्रतिस्थापित नहीं किया जा सकता है, और वस्तु को एक कैन को सौंपा varजा सकता है। हालाँकि, कहा गया है कि वस्तु अपनी आंतरिक स्थिति को संशोधित कर सकती है। उदाहरण के लिए:
class A(n: Int) {
var value = n
}
class B(n: Int) {
val value = new A(n)
}
object Test {
def main(args: Array[String]) {
val x = new B(5)
x = new B(6) // Doesn't work, because I can't replace the object created on the line above with this new one.
x.value = new A(6) // Doesn't work, because I can't replace the object assigned to B.value for a new one.
x.value.value = 6 // Works, because A.value can receive a new object.
}
}
इसलिए, भले ही हम सौंपी गई वस्तु को नहीं बदल सकते x, हम उस वस्तु की स्थिति को बदल सकते हैं। हालांकि, इसकी जड़ में, वहाँ था var।
अब, कई कारणों से अपरिवर्तनीयता एक अच्छी बात है। सबसे पहले, अगर कोई वस्तु आंतरिक स्थिति को नहीं बदलती है, तो आपको चिंता करने की ज़रूरत नहीं है कि आपके कोड का कोई अन्य हिस्सा इसे बदल रहा है। उदाहरण के लिए:
x = new B(0)
f(x)
if (x.value.value == 0)
println("f didn't do anything to x")
else
println("f did something to x")
यह मल्टीथ्रेड सिस्टम के साथ विशेष रूप से महत्वपूर्ण हो जाता है। एक मल्टीथ्रेडेड सिस्टम में, निम्नलिखित हो सकता है:
x = new B(1)
f(x)
if (x.value.value == 1) {
print(x.value.value) // Can be different than 1!
}
यदि आप valविशेष रूप से उपयोग करते हैं , और केवल अपरिवर्तनीय डेटा संरचनाओं का उपयोग करते हैं (अर्थात, सरणियों से बचें, सब कुछ scala.collection.mutableआदि), तो आप निश्चिंत हो सकते हैं कि ऐसा नहीं होगा। यही है, जब तक कि कुछ कोड नहीं है, शायद एक रूपरेखा भी है, प्रतिबिंब चालें करते हुए - प्रतिबिंब दुर्भाग्य से "अपरिवर्तनीय" मूल्यों को बदल सकता है।
यह एक कारण है, लेकिन इसके लिए एक और कारण है। जब आप उपयोग करते हैं var, तो आपको varकई उद्देश्यों के लिए पुन: उपयोग में लुभाया जा सकता है। इसकी कुछ समस्याएं हैं:
सीधे शब्दों में कहें, का उपयोग valकरना सुरक्षित है और अधिक पठनीय कोड की ओर जाता है।
हम दूसरी दिशा में जा सकते हैं। अगर valयह बेहतर है, तो आखिर क्यों var? ठीक है, कुछ भाषाओं ने उस मार्ग को लिया, लेकिन ऐसी परिस्थितियां हैं जिनमें परिवर्तनशीलता प्रदर्शन में सुधार करती है, बहुत कुछ।
उदाहरण के लिए, एक अपरिवर्तनीय लें Queue। जब आप या तो enqueueया dequeueउस में बातें, आप एक नया प्राप्त Queueवस्तु। फिर, आप इसमें सभी वस्तुओं को संसाधित करने के बारे में कैसे जाएंगे?
मैं एक उदाहरण के साथ इसके माध्यम से जाऊँगा। मान लीजिए कि आपके पास अंकों की एक कतार है, और आप उनमें से एक संख्या की रचना करना चाहते हैं। उदाहरण के लिए, यदि मेरे पास उस क्रम में 2, 1, 3 के साथ एक कतार है, तो मैं 213 नंबर प्राप्त करना चाहता हूं। आइए सबसे पहले इसे हल करें mutable.Queue:
def toNum(q: scala.collection.mutable.Queue[Int]) = {
var num = 0
while (!q.isEmpty) {
num *= 10
num += q.dequeue
}
num
}
यह कोड तेजी से और समझने में आसान है। इसकी मुख्य खामी यह है कि जो कतार पास की जाती है toNum, उसे संशोधित किया जाता है , इसलिए आपको इसकी एक प्रति पहले से बनानी होगी। यही वस्तु प्रबंधन है जो अपरिवर्तनीयता से आपको मुक्त करता है।
अब, आइए इसे गुप्त करें immutable.Queue:
def toNum(q: scala.collection.immutable.Queue[Int]) = {
def recurse(qr: scala.collection.immutable.Queue[Int], num: Int): Int = {
if (qr.isEmpty)
num
else {
val (digit, newQ) = qr.dequeue
recurse(newQ, num * 10 + digit)
}
}
recurse(q, 0)
}
क्योंकि मैं अपने बारे numमें जानने के लिए कुछ चर का पुन: उपयोग नहीं कर सकता , जैसे पिछले उदाहरण में, मुझे पुनरावृत्ति का सहारा लेना होगा। इस मामले में, यह एक पूंछ-पुनरावृत्ति है, जिसमें बहुत अच्छा प्रदर्शन है। लेकिन यह हमेशा ऐसा नहीं होता है: कभी-कभी कोई अच्छा (पठनीय, सरल) पूंछ पुनरावृत्ति समाधान नहीं होता है।
ध्यान दें, हालांकि, मैं एक ही समय में immutable.Queueऔर एक का उपयोग करने के लिए उस कोड को फिर से लिख सकता हूं var! उदाहरण के लिए:
def toNum(q: scala.collection.immutable.Queue[Int]) = {
var qr = q
var num = 0
while (!qr.isEmpty) {
val (digit, newQ) = qr.dequeue
num *= 10
num += digit
qr = newQ
}
num
}
यह कोड अभी भी कुशल है, इसके लिए पुनरावृत्ति की आवश्यकता नहीं है, और आपको यह चिंता करने की आवश्यकता नहीं है कि आपको कॉल करने से पहले अपनी कतार की प्रतिलिपि बनानी है या नहीं toNum। स्वाभाविक रूप से, मैं अन्य उद्देश्यों के लिए चर का पुन: उपयोग करने से बचता था, और इस फ़ंक्शन के बाहर कोई भी कोड उन्हें नहीं देखता है, इसलिए मुझे उनके मूल्यों के बारे में एक पंक्ति से दूसरी पंक्ति में बदलने के बारे में चिंता करने की आवश्यकता नहीं है - जब मैं स्पष्ट रूप से ऐसा करता हूं।
स्काला ने प्रोग्रामर को ऐसा करने का विकल्प चुना, अगर प्रोग्रामर ने इसे सबसे अच्छा समाधान माना। अन्य भाषाओं ने इस तरह के कोड को मुश्किल बनाने के लिए चुना है। मूल्य स्केला (और व्यापक उत्परिवर्तन के साथ कोई भी भाषा) भुगतान करता है कि संकलक के पास कोड को अनुकूलित करने में उतना अधिक मार्ग नहीं है जितना कि अन्यथा हो सकता है। जावा का उत्तर, रन-टाइम प्रोफ़ाइल के आधार पर कोड का अनुकूलन है। हम प्रत्येक पक्ष के पेशेवरों और विपक्षों के बारे में और आगे बढ़ सकते हैं।
निजी तौर पर, मुझे लगता है कि स्काला अभी के लिए सही संतुलन बनाता है। यह सही नहीं है, दूर तक। मुझे लगता है कि स्काला द्वारा क्लोजर और हास्केल दोनों को बहुत दिलचस्प धारणाएं नहीं अपनाई गई हैं, लेकिन स्काला की अपनी ताकत भी है। हम देखेंगे कि भविष्य क्या है।
q। यह एक प्रति बनाता है - ढेर पर, न कि ढेर - उस वस्तु के संदर्भ में । प्रदर्शन के लिए, आपको इस बारे में अधिक स्पष्ट होना होगा कि आप "क्या" बोल रहे हैं।
(x::xs).drop(1)बिल्कुल xs, "कॉपी" नहीं है xs) यहां से लिंक मैं समझ सकता था। tnx!
qrएक अपरिवर्तनीय कतार है, हर बार अभिव्यक्ति qr.dequeueको कहा जाता है यह एक बनाता है new Queue(देखें < github.com/scala/scala/blob/2.13.x/src/library/scala/collection/… )।
valअंतिम है, जो सेट नहीं किया जा सकता है। finalजावा में सोचो ।
val चर अपरिवर्तनीय हैं, लेकिन वे जिन वस्तुओं को संदर्भित करते हैं, वे नहीं होने चाहिए। लिंक के अनुसार स्टीफ़न ने पोस्ट किया: "यहां नामों के संदर्भ को एक अलग सरणी में इंगित करने के लिए नहीं बदला जा सकता है, लेकिन सरणी को संशोधित किया जा सकता है। दूसरे शब्दों में सरणी के सामग्री / तत्वों को संशोधित किया जा सकता है।" तो यह है कि finalजावा में कैसे काम करता है।
+=एक valठीक है के रूप में परिभाषित एक उत्परिवर्तित हैशमैप पर कॉल कर सकता हूं -मेरा मानना है कि finalजावा में इसका वास्तव में कैसे काम होता है
समान्य शब्दों में:
var = var iable
वैल = वी ariable + फिन अल
अंतर यह है कि एक varको फिर से सौंपा जा सकता है, जबकि ऐसा valनहीं किया जा सकता है। वास्तव में जो कुछ भी सौंपा गया है, उसकी परिवर्तनशीलता, या एक पक्ष मुद्दा है:
import collection.immutable
import collection.mutable
var m = immutable.Set("London", "Paris")
m = immutable.Set("New York") //Reassignment - I have change the "value" at m.
जहाँ तक:
val n = immutable.Set("London", "Paris")
n = immutable.Set("New York") //Will not compile as n is a val.
और इसलिए:
val n = mutable.Set("London", "Paris")
n = mutable.Set("New York") //Will not compile, even though the type of n is mutable.
यदि आप एक डेटा संरचना का निर्माण कर रहे हैं और इसके सभी क्षेत्र vals हैं, तो वह डेटा संरचना इसलिए अपरिवर्तनीय है, क्योंकि इसकी स्थिति परिवर्तित नहीं हो सकती है।
valअपरिवर्तनीय का varमतलब है और परस्पर का मतलब है।
C ++ के संदर्भ में सोच,
val x: T
गैर-स्थिर डेटा के लिए निरंतर सूचक के अनुरूप है
T* const x;
जबकि
var x: T
गैर-निरंतर डेटा के लिए गैर-स्थिर सूचक के अनुरूप है
T* x;
अनुकूलता valअधिक varहोने से कोडबेस की अपरिहार्यता बढ़ जाती है जिससे इसकी शुद्धता, सुगमता और समझने की सुविधा हो सकती है।
गैर-स्थिर डेटा के लिए निरंतर सूचक होने के अर्थ को समझने के लिए निम्नलिखित स्काला स्निपेट पर विचार करें:
val m = scala.collection.mutable.Map(1 -> "picard")
m // res0: scala.collection.mutable.Map[Int,String] = HashMap(1 -> picard)
यहां "पॉइंटर" val m स्थिर है, इसलिए हम इसे फिर से असाइन नहीं कर सकते हैं जैसे कि कुछ और
m = n // error: reassignment to val
हालाँकि हम वास्तव में गैर-स्थिर डेटा को स्वयं बदल सकते हैं जो mइसे पसंद करता है
m.put(2, "worf")
m // res1: scala.collection.mutable.Map[Int,String] = HashMap(1 -> picard, 2 -> worf)
"वैल का मतलब अपरिवर्तनीय होता है और var का अर्थ होता है।"
पैराप्रेज़ के लिए, "वैल का अर्थ है मान और संस्करण का मतलब है चर"।
एक ऐसा अंतर जो कंप्यूटिंग में बेहद महत्वपूर्ण होता है (क्योंकि वे दो अवधारणाएं बहुत सार बताती हैं कि प्रोग्रामिंग सभी के बारे में क्या है), और यह कि ओओ लगभग पूरी तरह से धुंधला करने में कामयाब रहा है, क्योंकि ओओ में, केवल स्वयंसिद्ध है कि "सब कुछ एक है" वस्तु "। और इसके परिणामस्वरूप, इन दिनों बहुत सारे प्रोग्रामर समझ / सराहना / पहचान नहीं करते हैं, क्योंकि उन्हें विशेष रूप से "ओओ रास्ता सोचने" में दिमाग लगाया गया है। अक्सर चर / उत्परिवर्तित वस्तुओं का उपयोग हर जगह की तरह किया जाता है , जब मूल्य / अपरिवर्तनीय वस्तुएं अक्सर बेहतर होती हैं।
वैल का मतलब अपरिवर्तनीय होता है और var का मतलब होता है
आप सोच सकते हैं valजावा प्रोग्रामिंग भाषा के रूप में finalकुंजी दुनिया या सी ++ भाषा constकुंजी दुनिया।
Valइसका अर्थ है, इसका अंतिम , पुन: असाइन नहीं किया जा सकता
जबकि, बाद में पुन: असाइनVar किया जा सकता है ।
यह नाम के रूप में सरल है।
var का मतलब यह अलग-अलग हो सकता है
वैल का मतलब होता है अमूर्त
वैल - मान टाइप किए गए संग्रहण स्थिरांक हैं। एक बार जब इसका मूल्य बनाया जाता है तो उसे फिर से सौंपा जा सकता है। कीवर्ड वैल के साथ एक नए मान को परिभाषित किया जा सकता है।
जैसे। वैल एक्स: इंट = 5
यहां टाइप वैकल्पिक है क्योंकि स्कैला इसे दिए गए मूल्य से अनुमान लगा सकता है।
Var - वैरिएबल टाइप की गई स्टोरेज इकाइयाँ होती हैं जिन्हें तब तक मूल्यों को सौंपा जा सकता है जब तक कि मेमोरी स्पेस आरक्षित न हो जाए।
जैसे। var x: Int = 5
दोनों भंडारण इकाइयों में संग्रहीत डेटा स्वचालित रूप से JVM द्वारा डी-आबंटित कर दिया जाता है, क्योंकि अब इनकी आवश्यकता नहीं है।
स्केला में मान वैरिएबल पर पसंद किए जाते हैं क्योंकि स्थिरता के कारण ये कोड को विशेष रूप से समवर्ती और मल्टीथ्रेड कोड में लाता है।
हालांकि कई पहले ही वैल और वर् के बीच अंतर का जवाब दे चुके हैं । लेकिन ध्यान देने वाली बात यह है कि वैल अंतिम कीवर्ड की तरह नहीं है ।
हम पुनरावर्तन का उपयोग करके वैल का मान बदल सकते हैं लेकिन हम कभी भी फाइनल का मान नहीं बदल सकते हैं। फाइनल वैल की तुलना में अधिक स्थिर है।
def factorial(num: Int): Int = {
if(num == 0) 1
else factorial(num - 1) * num
}
विधि पैरामीटर डिफ़ॉल्ट वैल द्वारा हैं और हर कॉल वैल्यू में बदला जा रहा है।
var qr = qएक प्रति बनाता हैq?