2013-10-20 3 views
22

Dеar स्काला,स्कैला में "केस" अज्ञात फ़ंक्शन वास्तव में कैसे काम करता है?

scala> val f1: ((Int, Int)) => Int = { case (a, b) => a + b } 
f1: ((Int, Int)) => Int = <function1> 

scala> val f2: (Int, Int) => Int = { case (a, b) => a + b } 
f2: (Int, Int) => Int = <function2> 

हुह ?!

scala> f1(1, 2) 
res2: Int = 3 

ठीक है ...

scala> def takesIntInt2Int(fun: (Int, Int) => Int) = fun(100, 200) 
takesIntInt2Int: (fun: (Int, Int) => Int)Int 

scala> def takesTuple2Int(fun: ((Int, Int)) => Int) = fun(100, 200) 
takesTuple2Int: (fun: ((Int, Int)) => Int)Int 

scala> takesIntInt2Int(f2) 
res4: Int = 300 

scala> takesIntInt2Int(f1) 
<console>:10: error: type mismatch; 
found : ((Int, Int)) => Int 
required: (Int, Int) => Int 
       takesIntInt2Int(f1) 
          ^

scala> takesTuple2Int(f1) 
res6: Int = 300 

scala> takesTuple2Int(f2) 
<console>:10: error: type mismatch; 
found : (Int, Int) => Int 
required: ((Int, Int)) => Int 
       takesTuple2Int(f2) 

ठीक है। और अब, इसे देखो!

scala> takesTuple2Int { case (a, b, c) => a + b + c } 
<console>:9: error: constructor cannot be instantiated to expected type; 
found : (T1, T2, T3) 
required: (Int, Int) 
       takesTuple2Int { case (a, b, c) => a + b + c } 
            ^

scala> takesIntInt2Int { case (a, b, c) => a + b + c } 
<console>:9: error: constructor cannot be instantiated to expected type; 
found : (T1, T2, T3) 
required: (Int, Int) 
       takesIntInt2Int { case (a, b, c) => a + b + c } 

की तरह, srsly? o_O दोनों परिणाम required: (Int, Int) त्रुटि में परिणाम।

फिर ऐसे अज्ञात कार्यों में case का उपयोग क्यों करें?

उत्तर

15

स्कैला संदर्भ (http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf) की धारा 8.5 देखें। { case (a, b) => a + b } अभिव्यक्ति अपेक्षित प्रकार के आधार पर अलग-अलग व्याख्या की गई है। f1 की अपनी परिभाषा में यह एक PartialFunction[(Int, Int), Int] जो एक Function1[(Int, Int), Int] को कास्ट किया गया है, यानी ((Int, Int)) => Int बनाया f2 की परिभाषा में, जबकि यह एक Function2[Int, Int, Int], अर्थात (Int, Int) => Int बनाया।

ये दो व्याख्याएं उन दो परिस्थितियों से संबंधित हैं जहां आप सामान्य रूप से किसी अज्ञात फ़ंक्शन में केस का उपयोग करेंगे।

एक अज्ञात कार्यों को लिखने के लिए है जो ट्यूपल्स स्वीकार करते हैं और उनके घटकों पर काम करते हैं, जैसा आपने f1 के साथ किया था। एक उदाहरण यह होगा कि आप या map विधि Map पर विधि को पास करेंगे, उदा। Map(1 -> 2, 3 -> 4) map { case (k, v) => k + v }

दूसरा एक अज्ञात फ़ंक्शन लिखने के लिए है जो match को अपने एकमात्र पैरामीटर पर करता है। आपका f2 ऐसा कर रहा है, लेकिन किसी भी उपयोगी तरीके से नहीं। एक उदाहरण अज्ञात फ़ंक्शन collect पर पास किया जाएगा, उदाहरण के लिए List(1, -2, 3) collect { case x if x > 0 => -x }

ध्यान दें कि दोनों को जोड़ा जा सकता है, यह f1 जैसे कार्यों को जटिल मिलान भी कर सकता है। उदाहरण के लिए, Map(1 -> 2, 3 -> 4) collect { case (k, v) if k < 2 => v }

संपादित करें: res2 टुपलिंग के कारण काम करता है। यदि कोई एप्लिकेशन चेक टाइप नहीं करता है, तो संकलक असफल होने से पहले एक टुपल में तर्क को लपेटने का प्रयास करेगा।

लेकिन यह केवल अनुप्रयोगों के लिए प्रयास किया गया है; जैसा कि आपने खोजा है, यह सामान्य रूपांतरण नहीं है। यह Function2[A, B, C] से Function1[(A, B), C] पर एक मान को अपग्रेड करने का प्रयास नहीं करेगा।

+1

'केस' कीवर्ड का उपयोग किये बिना यह सब करने में सक्षम होना बहुत अच्छा होगा। सामान्य डेवलपर के दृष्टिकोण से फ़ंक्शन और आंशिक फ़ंक्शन के लिए वाक्यविन्यास में अंतर क्यों? –

+2

@ माइकलस ईमानदार होने के लिए, यह हमेशा मुझे थोड़ा परेशान करता था। हास्केल और क्लोजर में फ़ंक्शन के पैरामीटर पर सीधे पैटर्न मिलान करने के लिए बहुत सरल वाक्यविन्यास होते हैं। – wingedsubmariner

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