2013-10-26 9 views
8
मैं अपने विश्वविद्यालय में प्रोग्रामिंग मानदंड सीख रहा हूँ

में समारोह को परिभाषित करने और इस पाठ्यक्रम के व्याख्याता है कि एक समारोह इस तरह से परिभाषित द्वारा प्रदान की सामग्री पढ़ने के लिए:डीईएफ़ या वैल स्काला

val double = (x: Int) => 2 * x 
double: Int => Int = <function1> 

लेकिन मेरे अपने अध्ययन से मैंने पाया और इस तरह के फ़ंक्शन को परिभाषित करने के लिए उपयोग किया गया:

def d (x: Int) = 2 * x 
d: (x: Int)Int 

मैं स्कैला के लिए नया हूं। 4 पैरामीटर के रूप में पारित करने पर

res21: Int = 8 

: और दोनों परिभाषाओं का एक परिणाम दे। अब मेरा मुख्य प्रश्न यह है कि व्याख्याता किसी कार्य को परिभाषित करने के लिए val का उपयोग क्यों करना पसंद करेगा? मैं इसे लंबे समय तक देखता हूं और वास्तव में तब तक जरूरी नहीं जब तक कि val का उपयोग कुछ अतिरिक्त फायदे नहीं देता जो मुझे नहीं पता। इसके अलावा मैं समझता हूं कि val का उपयोग कुछ प्लेसहोल्डर को बाद में प्रोग्राम में बनाता है, मैं गलती से val double = 5 लिख सकता हूं और फ़ंक्शन समाप्त हो जाएगा! इस चरण में मुझे काफी आश्वस्त है कि मैंने एक समारोह को परिभाषित करने का एक बेहतर तरीका सीखा है जब तक कोई मुझे अन्यथा नहीं बताएगा।

+0

मैं स्कैला के बारे में कुछ निश्चित कहने के लिए योग्य नहीं हूं, लेकिन क्या आपने वास्तव में 'डबल' के रूप में परिभाषित करने के बाद 'वैल डबल = 5' करने की कोशिश की है? मुझे लगता है कि एक बार परिभाषित होने के बाद एक नाम को फिर से परिभाषित करना असंभव होना चाहिए। किसी भी मामले में, 'वैल' और' डीफ 'दोनों एक ही परिणाम का उत्पादन करते हैं। अंतर केवल स्टाइलिस्ट है। अक्सर, 'def' के साथ फ़ंक्शन को परिभाषित करना अधिक स्पष्ट होता है लेकिन कभी-कभी इसे 'वैल' के साथ परिभाषित करने के लिए समझदारी होती है। यदि आप अनिश्चित हैं, तो मैं आपको 'def' के साथ जाने की अनुशंसा करता हूं क्योंकि इससे कोई भ्रम पैदा होने की संभावना कम होती है। – kqr

+0

हां, मैंने 'वैल डबल = 5' किया, टाइप किया 'डबल' और' res24: Int = 5' – Emanuel

+0

[स्केल में विधि और फ़ंक्शन के बीच अंतर] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/2529184/अंतर-बीच-विधि-और-फ़ंक्शन-इन-स्कैला) –

उत्तर

12

कड़ाई से बोलते हुए def d (x: Int) = 2 * x एक विधि है, एक समारोह नहीं है, हालांकि स्कैला हमारे लिए कार्यों में पारदर्शी रूप से परिवर्तित (लिफ्ट) विधियों को परिवर्तित कर सकता है। तो इसका मतलब है कि आप कहीं भी d विधि का उपयोग कर सकते हैं जिसके लिए Int => Int फ़ंक्शन की आवश्यकता होती है।

इस रूपांतरण को करने का एक छोटा ओवरहेड है, क्योंकि प्रत्येक बार एक नया फ़ंक्शन इंस्टेंस बनाया जाता है।

val double = (x: Int) => 2 * x 
def d (x: Int) = 2 * x 

def printFunc(f: Int => Int) = println(f.hashCode()) 

printFunc(double) 
printFunc(double) 
printFunc(d) 
printFunc(d) 

कौन सा तो जैसे उत्पादन में परिणाम है:: हम इस यहाँ हो रहा देख सकते हैं

1477986427 
1477986427 
574533740 
1102091268 

आप जब स्पष्ट रूप से एक val का उपयोग कर एक समारोह को परिभाषित करने को देख सकते हैं, हमारे कार्यक्रम केवल एक ही समारोह बनाता है और यह पुनः उपयोग कर लेता जब हम printFunc पर तर्क के रूप में पास होते हैं (हम एक ही हैश कोड देखते हैं)। जब हम def का उपयोग करते हैं, तो फ़ंक्शन में रूपांतरण हर बार होता है जब हम इसे printFunc पर पास करते हैं और हम विभिन्न हैश कोड के साथ फ़ंक्शन के कई उदाहरण बनाते हैं। Try it

कहा कि, प्रदर्शन भूमि के ऊपर छोटा है और अक्सर हमारे कार्यक्रम के लिए किसी भी असली फर्क नहीं करता, इसलिए def रों अक्सर कार्य परिभाषित करने के लिए उपयोग किया जाता है के रूप में कई लोग उन्हें अधिक संक्षिप्त और पढ़ने में आसान लगता है।

+2

[कुछ लड़के] (http://japgolly.blogspot.com.au/2013/10/scala-methods-vs-functions.html) हाल ही में एक बेंचमार्क चलाया, यह दिखा रहा है कि "ईटा-विस्तार" (एक विधि को उठाएं एक तर्क के रूप में इसे पारित करते समय एक समारोह) वास्तव में प्रदर्शन जुर्माना नहीं लेता है। –

+0

अच्छी पोस्ट। मुझे लगता है कि कचरा संग्रह में भी वृद्धि हो सकती है, लेकिन मुझे लगता है कि यह एक छोटा/अस्तित्वहीन भी होगा। – theon

0

क्योंकि आप निम्नलिखित की तरह कुछ हो सकता है:

abstract class BaseClass { 
    val intToIntFunc: Int => Int 
} 

class A extends BaseClass { 
    override val intToIntFunc = (i: Int) => i * 2 
} 

तो अपने उद्देश्य नहीं स्पष्ट एक बहुत ही सरल उदाहरण के साथ हो सकता है। लेकिन वह फ़ंक्शन मान स्वयं को उच्च आदेश फ़ंक्शंस में पारित किया जा सकता है: फ़ंक्शन जो पैरामीटर के रूप में कार्य करते हैं। यदि आप स्कैला संग्रह दस्तावेज में देखते हैं तो आपको कई विधियां दिखाई देगी जो पैरामीटर के रूप में कार्य करती हैं। यह एक बहुत ही शक्तिशाली और बहुमुखी उपकरण है, लेकिन लागत/लाभ स्पष्ट होने से पहले आपको एल्गोरिदम के साथ एक निश्चित जटिलता और परिचितता प्राप्त करने की आवश्यकता है।

मैं सुझाव देता हूं कि पहचानकर्ता नाम के रूप में "डबल" का उपयोग न करें। हालांकि कानूनी स्कैला, इसे डबल प्रकार के साथ भ्रमित करना आसान है।

5

स्कैला में, फ़ंक्शन मान मोनोमोर्फिक हैं (यानी वे टाइप पैरामीटर, उर्फ ​​"जेनेरिक" नहीं हो सकते हैं)।आप एक बहुरूपी समारोह चाहते हैं, आप एक पद्धति का उपयोग करके यह परिभाषित करते हुए इससे बचने के लिए, उदाहरण के लिए:

def headOption[A]: List[A] => Option[A] = { 
    case Nil => None 
    case x::xs => Some(x) 
} 

यह मान्य सिंटैक्स val headOption[A] लिखने के लिए नहीं होगा। ध्यान दें कि इससे पॉलीमोर्फिक फ़ंक्शन वैल्यू नहीं बनता है, यह केवल एक पॉलिमॉर्फिक विधि है, जो उपयुक्त प्रकार के मोनोमोर्फिक फ़ंक्शन मान को लौटाता है।

+0

+1 जो जागरूक होने के लिए एक महत्वपूर्ण अंतर है – theon

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