2012-03-14 18 views
22

का उपयोग कब करें मैं कुछ समय के लिए स्कैला सीखता हूं और विकल्प के उपयोग को स्पष्ट रूप से समझ नहीं सकता। जब मैं श्रृंखला कार्य करता हूं (docs के अनुसार) यह मुझे शून्य जांच से बचने में मदद करता है। यह मेरे लिए स्पष्ट है :)विकल्प

अगला मैं देखता हूं कि विकल्प डेवलपर के लिए संकेतक हो सकता है कि शून्य मूल्य यहां संभव है और इसे संभाला जाना चाहिए। क्या यह सच है? यदि हाँ मुझे विकल्प whereever का उपयोग करना चाहिए तो यह संभव है? उदाहरण

class Racer { 
    val car = new Car() 
} 

के लिए मैं रेसर वर्ग है और मुझे यकीन है कि कार फ़ील्ड रिक्त नहीं हो सकता है कर रहा हूँ (क्योंकि यह निरंतर है और जब मैं रेसर उदाहरण बनाने के एक मूल्य प्राप्त)। यहां विकल्प के लिए कोई ज़रूरत नहीं है।

class Racer { 
    var car = new Car() 
} 

यहां मैं इसे बना देता हूं ताकि कार बदल सके। और किसी के लिए कार को शून्य देने के लिए संभव है। क्या मुझे यहां विकल्प का उपयोग करना चाहिए? यदि हां, तो मुझे लगता है कि मेरे सभी वर्ग फ़ील्ड विकल्प के लिए उम्मीदवार हैं। और मेरा कोड इस तरह दिखता है

class Racer { 
    var car: Option[Car] = None 
    var currentRace: Option[Race] = None 
    var team: Option[Team] = None 
    ... 
} 

क्या यह अच्छा दिखता है? मेरे लिए यह एक तरह का विकल्प overusing लगता है।

def foo(): Result = { 
    if(something) 
     new Result() 
    else 
     null 
} 

मेरे पास एक विधि है जो शून्य को वापस कर सकती है। क्या मुझे इसके बजाय विकल्प वापस करना चाहिए? यदि मैं शून्य वापस करने के तरीके के लिए संभव है तो क्या मुझे हमेशा ऐसा करना चाहिए?

इसके बारे में कोई भी विचार उपयोगी होगा। अग्रिम में धन्यवाद!

मेरा प्रश्न Why option से समान है लेकिन मुझे लगता है कि यह वही नहीं है। यह के बारे में अधिक है,क्यों नहीं। :)

+1

अन्य उत्तरों के अलावा यह http://simply.liftweb.net/index-7.2.html –

+0

धन्यवाद पढ़ने का प्रयास करें। मैं एक नजर मार लूगां। – Soteric

उत्तर

34

आपको स्कैला में जितना संभव हो null से बचना चाहिए। यह वास्तव में जावा के साथ अंतःक्रियाशीलता के लिए मौजूद है। तो, null के बजाय, Option का उपयोग करें जब भी यह संभव हो कि कोई फ़ंक्शन या विधि "कोई मान" वापस नहीं लौटा सकती है, या जब यह सदस्य चर के लिए तर्कसंगत रूप से मान्य है तो "कोई मान नहीं" है।

अपने Racer उदाहरण के संबंध में: एक Racer वास्तव में वैध अगर यह एक car, currentRace और team नहीं है है? यदि नहीं, तो आपको उन सदस्य चर विकल्प नहीं बनाना चाहिए। उन्हें केवल विकल्प न बनाएं क्योंकि सैद्धांतिक रूप से उन्हें null पर असाइन करना संभव है; ऐसा केवल तभी करें जब आप तर्कसंगत रूप से इसे वैध Racer ऑब्जेक्ट मानते हैं यदि उनमें से किसी भी सदस्य चर के पास कोई मूल्य नहीं है।

दूसरे शब्दों में, यह दिखाएं कि null मौजूद नहीं है। स्कैला कोड में null का उपयोग कोड गंध है।

def foo(): Option[Result] = if (something) Some(new Result()) else None 

ध्यान दें कि Option साथ काम करने के कई उपयोगी तरीकों है।

val opt = foo() 

// You can use pattern matching 
opt match { 
    case Some(result) => println("The result is: " + result) 
    case None   => println("There was no result!") 
} 

// Or use for example foreach 
opt foreach { result => println("The result is: " + result) } 

इसके अलावा, अगर आप कार्यात्मक शैली में कार्यक्रम करना चाहते हैं, आप जितना संभव हो उतना परिवर्तनशील डेटा से बचना चाहिए, जिसका अर्थ है: var के उपयोग से बचने के बजाय val उपयोग करते हैं, अपरिवर्तनीय संग्रह का उपयोग करें और अपने खुद कक्षाएं बनाने जितना संभव हो उतना अपरिवर्तनीय।

+0

ग्रेट उत्तर। समझ में आता है। धन्यवाद। – Soteric

+11

"नाटक [आईएनजी] जैसा कि 'शून्य' मौजूद नहीं है, इसके अतिरिक्त, यदि आपको जावा कोड से निपटना है जो आपको 'foo' देता है जो' शून्य 'हो सकता है, तो आप' विकल्प (foo)' , जो 'शून्य' को 'कोई नहीं' में बदल देगा, और कुछ और 'कुछ (blah)' में बदल जाएगा। –

6

Options के पीछे विचार null से छुटकारा पाने के लिए है, इसलिए हाँ, आपको "null या एक मान" लौटने की बजाय उन्हें उपयोग करना चाहिए। यही कारण है कि, यदि आप वैकल्पिक फ़ील्ड (0..1 अन्य ऑब्जेक्ट्स के साथ संबंध) मॉडल करना चाहते हैं, तो Option का उपयोग करना निश्चित रूप से एक अच्छी बात है।

छोटी कमी यह है कि यह बहुत से वैकल्पिक क्षेत्र के साथ वर्ग की घोषणा को थोड़ा वर्बोज़ प्रस्तुत करता है, जैसा कि आपने उल्लेख किया था।

स्केल में एक और बात, आपको "अपरिवर्तनीय वस्तुओं" का उपयोग करने के लिए प्रोत्साहित किया जाता है, इसलिए आपके उदाहरण में, फ़ील्ड कुछ val एस होना चाहिए। ;)

+0

यदि मैं वैल का उपयोग करता हूं तो मैं मूल्य कैसे बदल सकता हूं? अगर मैं अपने रेसर के लिए एक नई कार चाहता हूं तो क्या होगा? – Soteric

+4

विचार एक नई वस्तु बनाने के लिए है जब एक नई कार जैसी घटना होती है: 'कक्षा दौड़ने वाला (नाम: स्ट्रिंग, कार: विकल्प [कार]) {def receanewar (सी: कार) = नया रेसर (नाम, कुछ (सी)); def breakHisCar = नया रेसर (नाम, कोई नहीं)} ' – Nicolas

9

यह स्काला में कार्यात्मक प्रोग्रामिंग की बात आती है, Optionnull की तुलना में काफी बेहतर है, क्योंकि यह टाइप-सुरक्षित है और कार्यात्मक प्रतिमान में अन्य निर्माणों के साथ अच्छा खेलता है।

विशेष रूप से, आप आसानी से Option पर उच्च-आदेश कार्यों का उपयोग करके बेवकूफ कोड लिख सकते हैं। यह Scala Option Cheat Sheet विषय पर एक उपयोगी पढ़ा है।

7

जबकि Option आपकी कक्षा परिभाषा वर्बोज़ को देख सकता है, तो वैकल्पिक यह नहीं पता कि आपको यह जांचने की आवश्यकता है कि कोई चर परिभाषित किया गया है या नहीं। मुझे लगता है कि आपके उदाहरण में, यदि आपकी कक्षा अपरिवर्तनीय थी (सभी फ़ील्ड val एस) थे, तो आपको Option एस की आवश्यकता नहीं होगी।

आपकी विधि foo के लिए, यदि आप शून्य लौटते हैं, तो आपको इसे दस्तावेज़ करने की आवश्यकता है और क्लाइंट को उस दस्तावेज़ को पढ़ने की आवश्यकता है। फिर ग्राहक की तरह कोड का एक समूह लिखेंगे: इसके बजाय यदि आपने foo परिभाषित एक Option[Result] वापस जाने के लिए

val result = foo(x) 
if (result != null) { 
    println(result) 
} 

, प्रकार प्रणाली ग्राहक एक अपरिभाषित परिणाम की संभावना को संभालने के लिए बाध्य करती है। उनके पास संग्रह कक्षाओं की पूरी शक्ति भी है।

result foreach println 

null के लिए परीक्षण के बजाय एक Option साथ संग्रह विधि का उपयोग का एक अतिरिक्त लाभ यह है कि अगर आपके विधि एक बहु तत्व संग्रह के लिए बढ़ा दिया गया है (एक List जैसे), तो आप को बदलने की जरूरत नहीं हो सकता है आपके बिल्कुल कोड उदाहरण के लिए, आप शुरू में अपना Racer मान सकते हैं कि केवल एक ही क्रू हो सकता है, इसलिए आप val crew: Option[Crew] को परिभाषित करते हैं और आप परीक्षण कर सकते हैं कि चालक दल 30 से अधिक पुराना है crew.forall(_.age > 30).getOrElse(false)। अब अगर आप val crew: List[Crew] को परिभाषा ही बदल अपने पुराने कोड अभी भी संकलन होगा और अब आप अगर अपने चालक दल के सदस्यों के सभी 30

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

val resource = Option(this.getClass.getResource("foo")) 

तो getResourcenull तो लौट आए resourceNone के बराबर होती है, और नहीं तो यह एक Some[URL] है। ठंडा!

दुर्भाग्य से, Option में कुछ ओवरहेड होने की संभावना है क्योंकि इसमें अतिरिक्त ऑब्जेक्ट सृजन शामिल है। हालांकि, उस ओवरहेड एक शून्य सूचक अपवाद की तुलना में कम है!

+0

कक्षा को अपरिवर्तनीय बनाने के लिए क्या आप हर बार जब मैं इसे बदलना चाहता हूं तो एक प्रतिलिपि बनाने की सलाह देते हैं? निकोलस की तरह कहा। – Soteric

+1

हां, लेकिन यह इस बात पर निर्भर करता है कि आप वस्तु का उपयोग कैसे कर रहे हैं। यदि आपके पास कई फ़ील्ड वाले ऑब्जेक्ट हैं जो आप अक्सर बदलते हैं, तो अपरिवर्तनीय समझ में नहीं आ सकता है। हालांकि, आप अक्सर अपने कोड को अलग-अलग डिज़ाइन कर सकते हैं ताकि आप कम उत्परिवर्तन कर रहे हों। यदि आपको उत्परिवर्तन की आवश्यकता है, तो आप एक विशेषता के माध्यम से उत्परिवर्तन छुपा सकते हैं (उदाहरण के लिए, सूची में एक उत्परिवर्तनीय फ़ील्ड है - आप इसे एक्सेस नहीं कर सकते हैं)। क्लाइंट उदाहरण के लिए – schmmd

+0

+1 –

संबंधित मुद्दे