सवाल स्कैला में कार्यों को परिभाषित करने के दो तरीके। अंतर क्या है?


यहां एक छोटा सा स्काला सत्र है जो कुछ कार्यों को परिभाषित करता है और कोशिश करता है:

scala> def test1(str: String) = str + str;    
test1: (str: String)java.lang.String

scala> test1("ab")
res0: java.lang.String = abab

अच्छी तरह से काम करता है।

scala> val test2 = test1
<console>:6: error: missing arguments for method test1 in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
       val test2 = test1
                   ^

उफ़।

scala> val test2 = test1 _
test2: (String) => java.lang.String = <function1>

scala> test2("ab")
res1: java.lang.String = abab

अच्छा काम करता है!

अब, मैंने देखा है _ तह करते समय वाक्यविन्यास (_ + _, आदि)। तो जैसा कि मैं इसे समझता हूँ _ मूल रूप से "एक तर्क" का अर्थ है। इसलिए test1 _ मूल रूप से एक तर्क के साथ एक समारोह का मतलब है, जो दिया जाता है test1"लेकिन वह क्यों नहीं है ठीक ठीक बस के समान ही test1? अगर मैं जोड़ता हूं तो इसमें कोई फर्क क्यों पड़ता है _?

तो मैंने अन्वेषण किया ...

scala> val test3 = (str: String) => str + str
test3: (String) => java.lang.String = <function1>

scala> test3("ab")
res2: java.lang.String = abab

scala> val test4 = test3
test4: (String) => java.lang.String = <function1>

यहां यह बिना काम करता है _! ए के बीच क्या अंतर है defएड फ़ंक्शन, और ए valएड फ़ंक्शन?


44
2018-02-15 20:57


मूल


रेक्स, मैं आपको कुछ समय बचाने के लिए जा रहा हूँ। आपने 1/27/2010 को मेलिंग सूची पर इसका उत्तर पहले ही दिया है। यह एक अच्छी प्रतिक्रिया थी इसलिए मैंने इसे बुकमार्क किया। scala-programming-language.1934581.n4.nabble.com/... - Bradford
@ ब्रैडफोर्ड - हे, धन्यवाद :) - Rex Kerr
मुझे लगता है कि स्कैला में "फ़ंक्शन" / "फ़ंक्शन को परिभाषित करने" शब्द के उपयोग के बारे में कुछ दुर्भाग्यपूर्ण भ्रम है। यहाँ तक की स्कैला में प्रोग्रामिंग कहता है कि def एक समारोह को परिभाषित करता है, लेकिन यह "फ़ंक्शन" की परिभाषा के आधार पर बिल्कुल सही नहीं है। अर्थात। एक विधि एक परिणाम देता है जो एक है के समारोह इसके पैरामीटर, लेकिन विधि एक नहीं है कार्य मूल्य या कार्य वस्तु। यह "फ़ंक्शन" शब्द के इन दो उपयोगों के बीच अंतर करने में मददगार होगा। - Knut Arne Vedaa
अप्रैल '10 से मेरे समान प्रश्न में उत्तरदायी उत्तर पढ़ें। stackoverflow.com/questions/2720486/... - (पीएस, मैं आपका अवतार QRd, बहुत मजाकिया!) - Synesso
संक्षेप में - कार्य बनाम विधि - Maxim


जवाब:


Defeded फ़ंक्शन और वैल्यू फ़ंक्शन के बीच कोई अंतर नहीं है:

scala> def test1 = (str: String) => str + str
test1: (String) => java.lang.String

scala> val test2 = test1
test2: (String) => java.lang.String = <function1>

scala> val test3 = (str: String) => str + str
test3: (String) => java.lang.String = <function1>

scala> val test4 = test2
test4: (String) => java.lang.String = <function1>

देख? ये सभी कार्य हैं, जो दर्शाए जाते हैं X => Y उनके पास टाइप करें।

scala> def test5(str: String) = str + str
test5: (str: String)java.lang.String

क्या आप एक देखते हैं X => Y प्रकार? यदि आप करते हैं, तो एक नेत्र रोग विशेषज्ञ देखें, क्योंकि कोई नहीं है। यहां का प्रकार है (X)Y, आमतौर पर एक को इंगित करने के लिए प्रयोग किया जाता है तरीका

वास्तव में, test1, test2, test3 तथा test4 सभी विधियां हैं, जो कार्य वापस करती हैं। test5 एक तरीका है जो एक देता है java.lang.String। इसके अलावा, test1 के माध्यम से test4 पैरामीटर न लें (केवल test1 हो सकता है, वैसे भी), जबकि test5 कर देता है।

तो, अंतर बहुत आसान है। पहले मामले में, आपने एक वैल को एक विधि असाइन करने का प्रयास किया था, लेकिन विधि के पैरामीटर को भरना नहीं था। तो यह तब तक असफल रहा जब तक आप एक पिछला अंडरस्कोर नहीं जोड़ा, जिसका मतलब था एक समारोह में मेरी विधि बारी

दूसरे उदाहरण में आपके पास एक फ़ंक्शन था, इसलिए आपको कुछ और करने की आवश्यकता नहीं थी।

एक विधि एक समारोह नहीं है, और इसके विपरीत। एक समारोह एक वस्तु का एक वस्तु है FunctionN कक्षाएं। एक विधि एक वस्तु से जुड़े कोड के कुछ टुकड़े के लिए एक हैंडल है।

स्टैक ओवरफ़्लो पर विधियों बनाम फ़ंक्शंस के बारे में विभिन्न प्रश्न देखें।


53
2018-02-16 01:03



है (X)Y एक प्रकार? ओह, और नए शब्द के लिए धन्यवाद। - Synesso
मुझे यह जवाब पसंद है। कुछ अनुवर्ती प्रश्न: 1)  क्या आप एक्स => वाई प्रकार देखते हैं? दूसरी पंक्ति के बारे में कैसे? क्या ऐसा नहीं है X => Y क्योंकि यह है ( तथा ) चारों ओर String? (अन्यथा मुझे पीले रंग के पृष्ठों में एक चिकित्सक की तलाश करनी होगी।) 2) आपके विवरण से मुझे ऐसा लगता है कि कार्य विधियों की तुलना में सख्ती से अधिक सामान्य हैं, और मैं आपका उपयोग कर सकता हूं test1के बजाय नोटेशन test5हर जगह नोटेशन? दोष क्या होगा? - aioobe
@ सिनेसियो हां, नहीं, तरह का। यह एक hypothetical विधि प्रकार के आरईपीएल का प्रतिनिधित्व है। - Daniel C. Sobral
@aioobe दूसरी पंक्ति नहीं है X => Y क्योंकि वहां नहीं है =>। कार्य विधियों की तुलना में धीमे होते हैं, और वे प्रकार पैरामीटर प्राप्त नहीं कर सकते हैं - इस पर स्टैक ओवरफ़्लो पर कहीं और चर्चा की गई है। - Daniel C. Sobral
scala> val test4 = test2   क्या यह स्वयंसेवक है, या आपका मतलब वैल है test4 = test3? - DenisFLASH


def जावा में विधियों को परिभाषित करने के तरीके के समान, आसपास के ऑब्जेक्ट / क्लास / विशेषता के भीतर एक विधि घोषित करता है। आप केवल उपयोग कर सकते हैं defअन्य वस्तुओं / कक्षाओं / लक्षणों के भीतर है। आरईपीएल में, आप आसपास के ऑब्जेक्ट को नहीं देख सकते क्योंकि यह "छुपा" है, लेकिन यह अस्तित्व में है।

आप एक असाइन नहीं कर सकते हैं def एक मूल्य के लिए, क्योंकि def एक मूल्य नहीं है - यह वस्तु में एक विधि है।

(x: T) => x * x घोषित करता है और तत्काल करता है कार्य वस्तु, जो रनटाइम पर मौजूद है। फंक्शन ऑब्जेक्ट्स अज्ञात वर्गों के उदाहरण होते हैं जो विस्तारित होते हैं FunctionN लक्षण। FunctionN लक्षण एक के साथ आते हैं apply तरीका। नाम apply विशेष है, क्योंकि इसे छोड़ा जा सकता है। अभिव्यक्ति f(x) में डूब गया है f.apply(x)

निचली पंक्ति है - चूंकि फ़ंक्शन ऑब्जेक्ट्स रनटाइम मान हैं जो ढेर पर मौजूद हैं, आप उन्हें मानों, चर और पैरामीटर को असाइन कर सकते हैं, या उन्हें वापसी मानों के रूप में विधियों से वापस कर सकते हैं।

मानों को निर्दिष्ट करने के तरीकों को हल करने के लिए (जो उपयोगी हो सकते हैं), स्कैला आपको किसी विधि से फ़ंक्शन ऑब्जेक्ट बनाने के लिए प्लेसहोल्डर वर्ण का उपयोग करने की अनुमति देता है। अभिव्यक्ति test1 _उपरोक्त आपके उदाहरण में वास्तव में विधि के चारों ओर एक रैपर समारोह बनाता है test1 - यह बराबर है x => test1(x)


58
2018-02-15 21:13



सरल अभी तक साफ जवाब, +1 - Muhammad Hewedy


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

पैरामीटर के स्थान पर लागू होने पर, प्रभाव को फ़ंक्शन में विधि को उठाना होता है।

scala> def test1(str: String) = str + str; 
test1: (str: String)java.lang.String

scala> val f1 = test1 _
f1: (String) => java.lang.String = <function1>

नोट, विधि प्रकार (स्ट्रिंग) => स्ट्रिंग का एक कार्य बन गया है।

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

उठाना आगे जा सकता है:

scala> val f2 = f1 _
f2: () => (String) => java.lang.String = <function0>

इस फ़ंक्शन को अन्य फ़ंक्शन में ले जाना। प्रकार के इस समय () => (स्ट्रिंग) => (स्ट्रिंग)

जो मैं बता सकता हूं, यह वाक्यविन्यास अंडरस्कोर के साथ सभी पैरामीटर को प्रतिस्थापित करने के बराबर है। उदाहरण के लिए:

scala> def add(i: Int, j: Int) = i + j
add: (i: Int,j: Int)Int

scala> val addF = add(_, _)
addF: (Int, Int) => Int = <function2>

scala> val addF2 = add _    
addF2: (Int, Int) => Int = <function2>

11
2018-02-15 23:00