2013-07-23 8 views
9

मेरे आवेदन में मुझे संग्रह में तत्वों को स्वैप करने की क्षमता की आवश्यकता है। (कार्यात्मक प्रोग्रामिंग मेंउत्परिवर्तनीय परिवर्तनीय बनाम संग्रहणीय संग्रह

  1. उपयोग परिवर्तनशील संग्रह val
  2. के रूप में घोषित या अपरिवर्तनीय संग्रह var के रूप में घोषित उपयोग करें (और हमेशा var में नई संग्रहण को पुन: असाइन)

लेकिन स्काला में: तो मैं एक विकल्प है) उत्परिवर्तन हमेशा से परहेज किया। तो क्या कम बुरा है: val का उपयोग करके घोषित संग्रह घोषित किया गया है या var के रूप में घोषित अपरिवर्तनीय संग्रह?

+1

अधिक संदर्भ के बिना, यह वास्तव में कोई फर्क नहीं पड़ता है। न तो एक कार्यात्मक दृष्टिकोण है। उत्परिवर्ती संग्रह शायद एक अपरिवर्तनीय var से बेहतर प्रदर्शन करेगा। – dbyrne

+0

@dbyrne * उत्परिवर्ती संग्रह शायद एक अपरिवर्तनीय var * व्हाओ से बेहतर प्रदर्शन करेगा? क्या वे एक ही टीम में दो खेल नहीं हैं? जैसे 'वैल misterMutableCollection = collection.mutable ....' –

+1

@ ओम-नाम-नाम एक अपरिवर्तनीय var के साथ, आपको एक पूरी तरह से नया संग्रह बनाना होगा और इसे स्वैप करना होगा। एक परिवर्तनीय वैल के साथ, आप इसे संग्रहीत करने के लिए मूल संग्रह और कॉल विधियों का उपयोग कर सकते हैं। – dbyrne

उत्तर

1

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

0

var पर पुन: असाइनमेंट को पढ़ने/बनाए रखना मुश्किल हो सकता है, खासकर यदि यह किसी विधि में एकाधिक स्थानों पर होता है, उदाहरण के लिए।

तो val के साथ, आपको कम से कम एक अपरिवर्तनीय संदर्भ मिलता है।

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

dbyrne सही ढंग से बताया गया है के रूप में: यदि यह परिवर्तनशील संग्रह (यदि आप उदाहरण के लिए एक कैश को लागू कर रहे हैं) अपरिवर्तनीय एक में कन्वर्ट करने के लिए संभव नहीं है, और परिवर्तनशील संग्रह सार्वजनिक एपीआई का हिस्सा है, तो एक var है बेहतर हो सकता है। इस मामले में एक और विकल्प है कि विधि में एक अपरिवर्तनीय प्रतिलिपि बनाना जो सार्वजनिक एपीआई लागू करता है।

+1

यह मेरी राय में अब तक का सबसे अच्छा जवाब है, लेकिन ऐसे मामले हैं जहां संग्रह के लिए यह अधिक महत्वपूर्ण है, और संदर्भ इतना महत्वपूर्ण नहीं है। यदि आप एक लाइब्रेरी लेखक हैं और आप यह सुनिश्चित करना चाहते हैं कि आपके एपीआई का उपयोग करने वाले किसी भी व्यक्ति ने इसे वापस करने के बाद संग्रह को म्यूटेट नहीं किया है, तो एक अपरिवर्तनीय var उचित होगा। – dbyrne

+0

@dbyrne टिप्पणी के लिए धन्यवाद; मैंने जवाब अपडेट कर लिया है। – Beryllium

4

आप एक var का उपयोग अपरिवर्तनीय संग्रह पकड़े यदि आप यह काफी स्वतंत्र रूप से प्रकाशित कर सकते हैं (हालांकि आप @volatile रूप var चिह्नित करना चाहते हो सकता है)। किसी भी समय किसी अन्य कोड को उस राज्य का केवल एक विशेष स्नैपशॉट मिल सकता है जो कभी नहीं बदल सकता है।

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

+0

क्या आप स्काला में @ वोलाटाइल कैसे काम करते हैं, इस बारे में थोड़ी अधिक जानकारी साझा कर सकते हैं? जो मैं समझता हूं उससे यह झंडा लगता है कि एक ही समय में एकाधिक थ्रेड इसे एक्सेस कर सकते हैं, लेकिन मुझे यकीन नहीं है कि यह एनोटेशन वास्तव में क्या बदलता है या चर के लिए करता है? धन्यवाद – LaloInDublin

+1

@ वोलाटाइल जावा में अस्थिर कीवर्ड के समान ही काम करता है। यह वीएम स्तर पर काम करता है। उदाहरण के लिए http://stackoverflow.com/questions/2694439/how-does- volatile-actually-work देखें। –

10

यह वास्तव में इस संग्रह पर व्यापक रूप से साझा करने की आवश्यकता पर निर्भर करता है। एक परिवर्तनीय संग्रह का लाभ यह है कि यह आमतौर पर अपरिवर्तनीय संग्रह से तेज़ होता है, और यह सुनिश्चित करने के बजाय कि आप विभिन्न संदर्भों से एक var सेट कर सकते हैं, एक ऑब्जेक्ट को पास करना आसान है। लेकिन जब से वे आप के नीचे से बाहर बदल सकते हैं, तो आप भी एक एकल पिरोया संदर्भ में सावधान रहना होगा:

import collection.mutable.ArrayBuffer 
val a = ArrayBuffer(1,2,3,4) 
val i = a.iterator 
i.hasNext    // True 
a.reduceToSize(0) 
i.next    // Boom! 

java.lang.IndexOutOfBoundsException: 0 
at scala.collection.mutable.ResizableArray$class.apply(ResizableArray.scala:43) 
    ... 

तो अगर यह व्यापक रूप से इस्तेमाल किया जा रहा है, तो आप पर विचार करना चाहिए कि क्या आप से बचने के लिए उचित रूप से सावधान किया जा सकता है इस तरह की समस्याएं। एक अप्रत्याशित संग्रह में var का उपयोग करना आम तौर पर सुरक्षित है; तो आप तारीख से बाहर हो सकते हैं, लेकिन कम से कम आप अपने चेहरे पर एक segfault के साथ नहीं गिरेंगे।

var v = Vector(1,2,3,4) 
val i = v.iterator 
i.hasNext   // True 
v = Vector[Int]() 
i.next    // 1 

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

var v = Vector(1,2,3,4) 
def timesTwo = v.map(_ * 2) 
timesTwo 
v  // Wait, it's still 1,2,3,4?! 

लेकिन तब यह या तो अद्यतन नहीं है, यह

a.map(_ * 2) // Map doesn't update, it produces a new copy! 

?: करता तो एक सामान्य नियम के रूप में,

  1. प्रदर्शन से एक का उपयोग करने की आवश्यकता है - यह एक विधि के भीतर
  2. स्थानीय गुंजाइश का उपयोग करें - परिवर्तनशील संग्रह का उपयोग
  3. अन्य थ्रेड/वर्गों के साथ साझा किया - अपरिवर्तनीय संग्रह का उपयोग
  4. एक वर्ग के भीतर
  5. कार्यान्वयन, सरल कोड - का उपयोग परिवर्तनशील संग्रह
  6. एक वर्ग के भीतर
  7. कार्यान्वयन, जटिल कोड - का उपयोग अपरिवर्तनीय

लेकिन आपको चाहिए शायद आप इसे जितनी बार चिपके रहते हैं उसका उल्लंघन करें।

1

एक सुरक्षित तरीका मैं का उपयोग किया है कुछ इस तरह काम करता है .. पहले इसे इस तरह सुरक्षित धागा बनाने के लिए अपने वर को छिपाने:

private[this] val myList: scala.collection.mutable.(whatever) 

निजी [इस] एक चर न केवल इस वर्ग को प्रतिबंधित करता है, लेकिन केवल इस सटीक उदाहरण के लिए। कोई अन्य चर इसे एक्सेस नहीं कर सकता है।

इसके बाद, एक सहायक समारोह इसके बारे में अपरिवर्तनीय संस्करण वापस जाने के लिए जब भी कुछ बाहरी जरूरतों इसके साथ काम करना:

def myListSafe = myList.toList (or some other safe conversion function like toMap, etc) 

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

0

रेक्स से सहमत, सबसे बड़ी चिंता यह है कि आप संग्रह साझा कर रहे हैं या नहीं। उस मामले में अपरिवर्तनीय उपयोग करें। एक अन्य विकल्प:

@volatile 
private var myList = immutable.List.empty[Foo] 
def theList = myList 
संबंधित मुद्दे