ठीक है, यहां पूर्ण टूटना है।
def value: Int = ???
def method(): Int = ???
def f1(f:() => Int) = ???
def f2(f: => Int) = ???
f1(value) // fails
f1(method) // works
f2(value) // works
f2(method) // works with a warning "empty-paren method accessed as parameterless"
-
f1 (मूल्य)
यह एक विफल रहता है क्योंकि f1
एक यूनिट => इंट समारोह उम्मीद कर रही है, लेकिन एक इंट मूल्य दिया जाता है।
-
f1 (विधि)
यह एक काम करता है क्योंकि f1
एक समारोह की उम्मीद कर रहा है, और एक विधि दी गई है। यहां अंतर है: विधि स्कैला में कोई मान नहीं है; यह अपने आप पर मौजूद नहीं हो सकता है और संदर्भ में एक विशेषता है जिसे परिभाषित किया गया है (वर्ग, विशेषता, वस्तु आदि)। कार्य एक मूल्य है; इसे एक संग्रह में रखा जा सकता है, जिसे किसी अन्य फ़ंक्शन में तर्क के रूप में लिया जाता है, फ़ंक्शन इत्यादि से लौटाया जाता है। जब कंपाइलर फ़ंक्शन की अपेक्षा कर रहा है और उसे विधि दी जाती है, तो यह ईटा विस्तार करता है। एक समारोह को देखते हुए उदा। f: (a: Int, b: Int) => Int
, ईटा विस्तार हस्ताक्षर को संरक्षित करते समय चारों ओर एक और परत के निर्माण की प्रक्रिया है, इसलिए यह (a: Int, b: Int) => f(a, b)
बन जाता है। यह तकनीक उपयोगी है क्योंकि हम तरीकों को कार्य में बदल सकते हैं। कुछ विधि def f(a: Int): Int = ???
को देखते हुए, हम int => int out of: (a: Int) => f(a)
के फ़ंक्शन को बनाने के लिए ईटा-विस्तार कर सकते हैं। यदि आप रुचि रखते हैं तो मैंने कुछ समय पहले इस बारे में blog post लिखा था।
-
f2 (मूल्य)
वर्क्स आश्चर्य के बिना, लेकिन तथ्य यह है कि भेजे गए मान को हर बार यह प्रयोग किया जाता है पहुँचा जा सकता है पर ध्यान देना समारोह शरीर
-
f2 (विधि)
काम करता है, लेकिन एक चेतावनी है कि हम एक विधि लागू कर रहे हैं कि खाली कोष्ठक के साथ का उपयोग करके परिभाषित किया गया है के साथ कोई कोष्ठक। अच्छा अभ्यास ब्रांड्स के बिना विधियों का उपयोग करना है (उदा। f
) जब वे केवल एक मान का प्रतिनिधित्व करते हैं, लेकिन प्रत्येक बार जब इसे एक्सेस किया जाता है, तो पुन: गणना की जाती है, उदा। numberOfUpvotes
, और खाली कोष्ठक के साथ विधियों का उपयोग करने के लिए (उदा। f()
) जब किसी प्रकार का साइड-इफेक्ट किया जाता है और इसलिए विधि idempotent नहीं है, उदा। createSnapshot()
(फिर से, यह पूरी तरह से कार्यात्मक कोड में मौजूद नहीं होना चाहिए)।
सलाह का शब्द: अपने दिमाग को किसी चीज के बदले में न रखें। प्रतिस्थापन का उपयोग न करें। अगर किसी को किसी फ़ंक्शन की आवश्यकता होती है, तो उसे एक फ़ंक्शन प्रदान करें। यदि इसे एक मूल्य की आवश्यकता है, तो एक मूल्य प्रदान करें। यदि किसी विधि को माता-पिता के बिना परिभाषित किया गया है, तो इसे बिना माता-पिता के आह्वान करें। यदि उसके माता-पिता हैं, तो इसे माता-पिता के साथ बुलाओ।
यदि आपको विधि से कार्य करने की आवश्यकता है और कंपाइलर फ़ंक्शन की अपेक्षा कर रहा है, तो ईटा-विस्तार स्वचालित रूप से हो जाएगा। यदि यह किसी फ़ंक्शन की अपेक्षा नहीं कर रहा है, तो आपको इसे मैन्युअल रूप से करने की आवश्यकता है।
def f(): Int = ???
val a = f // no function context; a is a string
val b:() => Int = f // b is a function Unit => Int
val c = f2 _ // c is a function Unit => Int
अंतिम मामला आंशिक रूप से लागू फ़ंक्शन है। मुझे लगता है कि मैं अब बहुत व्यापक जा रहा हूं इसलिए मैं यहां रुक जाऊंगा। मुझे आशा है कि इससे मदद मिलेगी।
आपके उदाहरण निश्चित रूप से * समकक्ष नहीं हैं। पहला व्यक्ति 'कोशिश करें [() ⇒ Int] ', दूसरा' प्रयास करें [int]'। प्रकार '() ⇒ Int' के आपके फ़ंक्शन तर्क को' ⇒ टी 'में 'टी'' (⇒ Int 'के साथ परिवर्तित किया जाता है। –
यहां कुछ अच्छी जानकारी है: https://tpolecat.github.io/2014/06/26/call-by-name.html – nevets1219
वे एक-दूसरे को प्रतिस्थापित नहीं करते हैं और वे स्कैला कंपाइलर द्वारा एक-दूसरे में परिवर्तित नहीं होते हैं। वे बस अलग-अलग चीजें हैं और आमतौर पर विभिन्न उद्देश्यों की पूर्ति करते हैं। –