2012-07-08 20 views
81

में वैल-म्यूटेबल बनाम वैर-इमटेबल, क्या एक अपरिवर्तनीय संग्रह के साथ var का उपयोग कर एक परिवर्तनीय संग्रह बनाम वैल का उपयोग करने के दौरान स्कैला में कोई दिशानिर्देश हैं? या क्या आप वास्तव में एक अपरिवर्तनीय संग्रह के साथ मूल्य के लिए लक्ष्य करना चाहिए?स्केल

तथ्य यह है कि दोनों प्रकार के संग्रह मुझे बहुत पसंद करते हैं, और अक्सर मैं नहीं जानता कि यह विकल्प कैसे बनाया जाए।

+0

उदाहरण के लिए देखें http://stackoverflow.com/questions/10999024/scala-var-list-vs-val-mutablelist/11002321#11002321 –

उत्तर

87

बहुत आम सवाल, यह एक। मुश्किल चीज डुप्लिकेट ढूंढ रही है।

आप निर्देशात्मक पारदर्शिता के लिए प्रयास करना चाहिए। इसका अर्थ यह है कि, यदि मेरे पास "ई" अभिव्यक्ति है, तो मैं val x = e बना सकता हूं, और e को x के साथ प्रतिस्थापित कर सकता हूं। यह वह संपत्ति है जो उत्परिवर्तन टूट जाती है। जब भी आपको डिज़ाइन निर्णय लेने की आवश्यकता होती है, तो संदर्भित पारदर्शिता के लिए अधिकतम करें।

एक व्यावहारिक मामले के रूप में, एक विधि-स्थानीय var सबसे सुरक्षित var मौजूद है, क्योंकि यह विधि से बच नहीं है। यदि विधि कम है, तो भी बेहतर है। यदि ऐसा नहीं है, तो अन्य विधियों को निकालने से इसे कम करने का प्रयास करें।

दूसरी ओर, एक परिवर्तनशील संग्रह संभावित से बचने के लिए, भले ही यह नहीं है है। कोड बदलते समय, आप इसे अन्य तरीकों से पास करना चाहते हैं, या इसे वापस कर सकते हैं। यही वह चीज है जो संदर्भित पारदर्शिता को तोड़ देती है।

किसी ऑब्जेक्ट (एक फ़ील्ड) पर, बहुत कुछ वही होता है, लेकिन अधिक गंभीर परिणामों के साथ। किसी भी तरह से ऑब्जेक्ट में राज्य होगा और इसलिए, संदर्भित पारदर्शिता तोड़ें। लेकिन एक परिवर्तनीय संग्रह होने का मतलब है कि ऑब्जेक्ट स्वयं भी इसे बदलने वाले व्यक्ति का नियंत्रण खो सकता है।

+34

मेरे दिमाग में अच्छी, नई बड़ी तस्वीर: 'mutable var' पर' mutable val' पर 'अपरिवर्तनीय var' पर' अपरिवर्तनीय वैल' पसंद करें। 'म्यूटेबल वैल' पर विशेष रूप से 'अपरिवर्तनीय var'! –

+2

ध्यान रखें कि आप स्थानीय म्यूटेबल 'var' पर अभी भी बंद कर सकते हैं (जैसा कि एक साइड-इफेक्टिंग" फ़ंक्शन "है जो इसे बदल सकता है) को रिसाव कर सकता है। अपरिवर्तनीय संग्रहों का उपयोग करने की एक और अच्छी विशेषता यह है कि आप 'var' mutates के बावजूद पुरानी प्रतियों को कुशलतापूर्वक रख सकते हैं। –

+1

टीएल; डॉ: पसंद करें 'var x: सेट [Int] '** ** ** वैल एक्स: mutable.Set [int]' चूंकि आप किसी अन्य फ़ंक्शन में 'x' पास करते हैं, तो पूर्व मामले में, आप हैं निश्चित रूप से, वह फ़ंक्शन आपके लिए 'x' को म्यूट नहीं कर सकता है। – pathikrit

13

यदि आप अपरिवर्तनीय संग्रह के साथ काम करते हैं और आपको उन्हें "संशोधित" करने की आवश्यकता है, उदाहरण के लिए, उन्हें लूप में तत्व जोड़ें, तो आपको var एस का उपयोग करना होगा क्योंकि आपको परिणामी संग्रह कहीं और स्टोर करना होगा। यदि आप केवल अपरिवर्तनीय संग्रह से पढ़ते हैं, तो val एस का उपयोग करें।

सामान्य रूप से, सुनिश्चित करें कि आप संदर्भ और वस्तुओं को भ्रमित नहीं करते हैं। val एस अपरिवर्तनीय संदर्भ हैं (सी में निरंतर पॉइंटर्स)। यही कारण है, जब आप val x = new MutableFoo() उपयोग करते हैं, आप में सक्षम करने के लिए वस्तु कि x अंक बदलने के लिए होगा, लेकिन आप में सक्षम जो करने के लिएx अंक वस्तु को बदलने के लिए नहीं होगा। यदि आप var x = new ImmutableFoo() का उपयोग करते हैं तो विपरीत होता है। मेरी शुरुआती सलाह उठाकर: यदि आपको किसी संदर्भ बिंदु पर बदलने की आवश्यकता नहीं है, तो val एस का उपयोग करें।

+1

'var immutable = something(); अपरिवर्तनीय = immutable.update (x) 'एक अपरिवर्तनीय संग्रह का उपयोग करने के उद्देश्य को हरा देता है। आपने पहले ही रेफरेंसियल पारदर्शिता छोड़ दी है और आप आमतौर पर बेहतर समय जटिलता के साथ एक परिवर्तनीय संग्रह से एक ही प्रभाव प्राप्त कर सकते हैं। चार संभावनाओं ('वाल' और 'var', उत्परिवर्तनीय और अपरिवर्तनीय) में से, यह कम से कम समझ में आता है। मैं अक्सर 'वैल म्यूटेबल' का उपयोग करता हूं। –

+3

@JimPivarski मैं असहमत हूं, दूसरों के रूप में, डैनियल के जवाब और पीटर द्वारा टिप्पणी देखें। यदि आपको डेटा संरचना को अपडेट करने की आवश्यकता है, तो एक म्यूटेबल वैल के बजाय एक अपरिवर्तनीय var का उपयोग करने का लाभ यह है कि आप संरचना के संदर्भों को रिसाव कर सकते हैं, यह जोखिम है कि इसे दूसरों द्वारा संशोधित किया जाता है जिससे आपकी स्थानीय धारणाएं टूट जाती हैं। इन "दूसरों" के लिए नुकसान यह है कि वे पुराने डेटा पढ़ सकते हैं। –

+0

मैंने अपना दिमाग बदल दिया है और मैं आपसे सहमत हूं (मैं इतिहास के लिए अपनी मूल टिप्पणी छोड़ रहा हूं)। मैंने तब से इसका उपयोग किया है, खासकर 'var सूची में: सूची [एक्स] = शून्य; सूची = आइटम :: सूची; ... 'और मैं भूल गया था कि मैंने एक बार अलग लिखा था। –

1

मुझे लगता है कि इस ब्लॉग पोस्ट में उदाहरण अधिक प्रकाश डाले जाएंगे, क्योंकि कॉम्बो का उपयोग करने के सवाल को समवर्ती परिदृश्यों में और भी महत्वपूर्ण हो जाता है: importance of immutability for concurrency। और जब हम इसमें हैं, तो सिंक्रनाइज़ बनाम @ वोलाटाइल बनाम कुछ पसंदीदा परमाणु संदर्भ: three tools

9

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

बेशक, हम संग्रहकर्ता को संग्रह भेजने के बाद भी संख्या एकत्र कर रहे हैं। और मान लें कि लॉगिंग प्रक्रिया में कुछ ओवरहेड है जो वास्तविक लॉगिंग में देरी करता है। उम्मीद है कि आप देख सकते हैं कि यह कहां जा रहा है।

अगर हम एक परिवर्तनशील val में इस संग्रह की दुकान, (परिवर्तनशील है क्योंकि हम लगातार यह करने के लिए जोड़ रहे हैं), इसका मतलब है कि प्रक्रिया प्रवेश कर एक ही वस्तु है कि अभी भी हमारे संग्रह की प्रक्रिया के द्वारा अद्यतन किया जा रहा पर नजर रखेंगे, । उस संग्रह को किसी भी समय अपडेट किया जा सकता है, और इसलिए जब लॉग इन करने का समय हो तो हम वास्तव में हमारे द्वारा भेजे गए संग्रह को लॉग इन नहीं कर सकते हैं।

यदि हम एक अपरिवर्तनीय var का उपयोग करते हैं, तो हम लॉगर को एक अपरिवर्तनीय डेटा संरचना भेजते हैं। जब हम अपने संग्रह में अधिक संख्याएं जोड़ते हैं, तो हम को नई अपरिवर्तनीय डेटा संरचना के साथ बदल देंगे। इसका मतलब यह नहीं है कि लॉगर को भेजा गया संग्रह बदल दिया गया है! यह अभी भी भेजे गए संग्रह का संदर्भ दे रहा है। तो हमारा लॉगर वास्तव में प्राप्त संग्रह को लॉग करेगा।

+0

[यहां] (https://gist.github.com/jmazin/8583395) एक उदाहरण है (इस उदाहरण का !!) – jmazin

-1

var immutable बनाम val mutable

इस सवाल का जवाब कई उत्कृष्ट के अलावा। यहां एक साधारण उदाहरण है, जो val mutable के संभावित खतरों को दर्शाता है:

उत्परिवर्तनीय वस्तुओं को विधियों के अंदर संशोधित किया जा सकता है, जो उन्हें पैरामीटर के रूप में लेते हैं, जबकि पुन: असाइनमेंट की अनुमति नहीं है।

import scala.collection.mutable.ArrayBuffer 

object MyObject { 
    def main(args: Array[String]) { 

     val a = ArrayBuffer(1,2,3,4) 
     silly(a) 
     println(a) // a has been modified here 
    } 

    def silly(a: ArrayBuffer[Int]): Unit = { 
     a += 10 
     println(s"length: ${a.length}") 
    } 
} 

परिणाम:

length: 5 
ArrayBuffer(1, 2, 3, 4, 10) 

कुछ इस तरह, var immutable साथ ऐसा नहीं हो सकता क्योंकि रीअसाइनमेंट अनुमति नहीं है:

में
object MyObject { 
    def main(args: Array[String]) { 
     var v = Vector(1,2,3,4) 
     silly(v) 
     println(v) 
    } 

    def silly(v: Vector[Int]): Unit = { 
     v = v :+ 10 // This line is not valid 
     println(s"length of v: ${v.length}") 
    } 
} 

परिणाम:

error: reassignment to val 

समारोह paramet के बाद से ers को val के रूप में माना जाता है इस पुन: असाइनमेंट की अनुमति नहीं है।

+0

यह गलत है। आपको उस त्रुटि का कारण यह है क्योंकि आपने अपने दूसरे उदाहरण में वेक्टर का उपयोग किया था, जो डिफ़ॉल्ट रूप से अपरिवर्तनीय है। यदि आप एक ऐरेबफर का उपयोग करते हैं तो आप देखेंगे कि यह ठीक से संकलित करता है और वही काम करता है जहां यह नए तत्व में जोड़ता है और उत्परिवर्तित बफर को प्रिंट करता है। https://pastebin.com/vfq7ytaD – EdgeCaseBerg

+0

@EdgeCaseBerg, मैं जानबूझकर अपने दूसरे उदाहरण में वेक्टर का उपयोग कर रहा हूं, क्योंकि मैं यह दिखाने की कोशिश कर रहा हूं कि पहले उदाहरण 'म्यूटेबल वैल' का व्यवहार 'अपरिवर्तनीय var' के साथ संभव नहीं है । यहाँ क्या गलत है? – Akavall

+0

आप यहां से संतरे से सेब की तुलना कर रहे हैं। वेक्टर में '+ =' विधि नहीं है जैसे सरणी बफर। आपके उत्तरों का तात्पर्य है कि '+ =' 'x = x + y' जैसा ही है जो यह नहीं है। आपके कथन जो फ़्रेम को फ़ंक्शन करते हैं उन्हें वैल के रूप में माना जाता है और आपको त्रुटि का पता चलता है लेकिन केवल इसलिए कि आपने '=' का उपयोग किया है। आप एक ऐरेबफर के साथ एक ही त्रुटि प्राप्त कर सकते हैं, इसलिए संग्रह उत्परिवर्तन यहां वास्तव में प्रासंगिक नहीं है। तो यह एक अच्छा जवाब नहीं है क्योंकि ओपी के बारे में बात करने पर यह नहीं हो रहा है। यद्यपि यह एक म्यूटेबल संग्रह पास करने के खतरों का एक अच्छा उदाहरण है, यदि आप का इरादा नहीं था। – EdgeCaseBerg