2011-01-18 11 views
64

इस निर्माण से स्कैला में टाइप मिस्चैच त्रुटि क्यों होती है?समझ के लिए स्कैला पर मिस्चैच टाइप करें

for (first <- Some(1); second <- List(1,2,3)) yield (first,second) 

<console>:6: error: type mismatch; 
found : List[(Int, Int)] 
required: Option[?] 
     for (first <- Some(1); second <- List(1,2,3)) yield (first,second) 

अगर मैं सूची के साथ कुछ स्विच यह ठीक संकलित:

for (first <- List(1,2,3); second <- Some(1)) yield (first,second) 
res41: List[(Int, Int)] = List((1,1), (2,1), (3,1)) 

यह भी ठीक काम करता है:

for (first <- Some(1); second <- Some(2)) yield (first,second) 
+2

स्केल को असफल उदाहरण में वापस आने की क्या उम्मीद थी? –

+0

जब मैं इसे लिख रहा था तो मैंने सोचा कि मुझे एक विकल्प मिलेगा [सूची [(Int, Int)]]। –

उत्तर

99

comprehensions लिए map या flatMap विधि के लिए कॉल में बदला जाता है । उदाहरण के इस एक के लिए:

List(1).flatMap(x => List(1,2,3).map(y => (x,y))) 

इसलिए, पहले पाश मूल्य (इस मामले, List(1) में) flatMap विधि कॉल प्राप्त होगा:

for(x <- List(1) ; y <- List(1,2,3)) yield (x,y) 

कि हो जाता है। flatMapList पर List लौटाता है, इसलिए समझ के परिणाम निश्चित रूप से List होगा। (यह मेरे लिए नया था: comprehensions हमेशा Seq रों में धाराओं में परिणाम नहीं के लिए, जरूरी नहीं कि यहां तक ​​कि।)

अब, flatMapOption में घोषित किया जाता है पर एक नज़र डालें:

def flatMap [B] (f: (A) ⇒ Option[B]) : Option[B] 

रखें यह दिमाग में है। चलो देखते हैं कैसे समझ (Some(1) के साथ) के लिए गलत नक्शे के एक दृश्य में परिवर्तित हो जाता कॉल:

Some(1).flatMap(x => List(1,2,3).map(y => (x, y))) 

अब, यह देखने के लिए कि flatMap कॉल के पैरामीटर कुछ है कि एक List देता है आसान है, लेकिन आवश्यकतानुसार Option नहीं।

आदेश बात ठीक करने के लिए, आप निम्न कर सकते हैं:

for(x <- Some(1).toSeq ; y <- List(1,2,3)) yield (x, y) 

कि ठीक संकलित करता है। यह ध्यान देने योग्य है कि OptionSeq का उपप्रकार नहीं है, जैसा अक्सर माना जाता है।

4

शायद यह विकल्प के साथ कुछ करने के लिए एक इटरटेबल नहीं है। निहित Option.option2Iterable उस मामले को संभालेगा जहां संकलक दूसरे को एक इटेबल होने की उम्मीद कर रहा है। मुझे उम्मीद है कि लूप वैरिएबल के प्रकार के आधार पर कंपाइलर जादू अलग है।

24

समझने के लिए एक आसान युक्ति, समझ के लिए इस मामले में पहले जनरेटर, विकल्प [Int] के संग्रह को वापस करने का प्रयास करेगा। इसलिए, यदि आप से शुरू करते हैं तो कुछ (1) आपको विकल्प [टी] के परिणाम की अपेक्षा करनी चाहिए।

यदि आप सूची प्रकार का परिणाम चाहते हैं, तो आपको एक सूची जेनरेटर से शुरू करना चाहिए।

यह प्रतिबंध क्यों है और यह नहीं मानते कि आप हमेशा किसी प्रकार का अनुक्रम चाहते हैं? आपके पास ऐसी स्थिति हो सकती है जहां Option लौटने का अर्थ हो।हो सकता है कि आपके पास Option[Int] है कि आप Option[List[Int]] प्राप्त करने के लिए कुछ के साथ गठबंधन करना चाहते हैं, निम्न कार्य के साथ कहें: (i:Int) => if (i > 0) List.range(0, i) else None; आप तो इस बारे में और जब चीजें नहीं है "मतलब" कोई नहीं मिल सकता है:

val f = (i:Int) => if (i > 0) Some(List.range(0, i)) else None 
for (i <- Some(5); j <- f(i)) yield j 
// returns: Option[List[Int]] = Some(List(0, 1, 2, 3, 4)) 
for (i <- None; j <- f(i)) yield j 
// returns: Option[List[Int]] = None 
for (i <- Some(-3); j <- f(i)) yield j 
// returns: Option[List[Int]] = None 

कैसे comprehensions के लिए सामान्य मामले में विस्तार कर रहे हैं एक बहुत ही सामान्य तंत्र प्रकार M[T] का एक उद्देश्य गठबंधन करने के लिए वास्तव में कर रहे हैं M[U] प्रकार की ऑब्जेक्ट प्राप्त करने के लिए (T) => M[U] फ़ंक्शन के साथ। आपके उदाहरण में, एम विकल्प या सूची हो सकती है। आम तौर पर यह एक ही प्रकार M होना चाहिए। तो आप सूची के साथ विकल्प गठबंधन नहीं कर सकते हैं। अन्य चीजों के उदाहरणों के लिए जो M हो सकते हैं, subclasses of this trait पर देखें।

List[T](T) => Option[T] के साथ संयोजन क्यों किया गया जब आपने सूची के साथ शुरुआत की थी? इस मामले में पुस्तकालय एक सामान्य प्रकार का उपयोग करता है जहां यह समझ में आता है। तो आप ट्रैवर्सबल के साथ सूची को जोड़ सकते हैं और विकल्प से ट्रैवर्सबल में एक निहित रूपांतरण है।

नीचे की रेखा यह है: इस बारे में सोचें कि आप किस प्रकार की अभिव्यक्ति वापस लौटना चाहते हैं और उस जनरेटर के रूप में उस प्रकार से शुरू करें। यदि आवश्यक हो तो उस प्रकार में लपेटें।

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