2013-07-19 7 views
25

अज्ञात फ़ंक्शन में एक स्पष्ट वापसी कथन (return कीवर्ड का उपयोग करने वाला) क्यों नामांकित फ़ंक्शन से वापस लौटाता है, न केवल अज्ञात फ़ंक्शन से?अज्ञात कार्यों में स्कैला रिटर्न स्टेटमेंट

उदा। एक प्रकार की त्रुटि में निम्नलिखित कार्यक्रम के परिणाम:

def foo: String = { 
    ((x: Integer) => return x) 
    "foo" 
} 

मैं जानता हूँ कि यह return कीवर्ड से बचने के लिए अनुशंसा की जाती है, लेकिन मैं में क्यों स्पष्ट और निहित वापसी बयान गुमनाम कार्यों में एक अलग अर्थ विज्ञान है इच्छुक हूँ।

निम्नलिखित उदाहरण में, m के बाद रिटर्न स्टेटमेंट "जीवित रहता है" निष्पादन समाप्त हो गया है, और प्रोग्राम को रन-टाइम अपवाद में परिणाम मिलता है। यदि अज्ञात फ़ंक्शन संलग्न कार्य से वापस नहीं लौटे, तो उस कोड को संकलित करना संभव नहीं होगा।

def main(args: Array[String]) { 
    m(3) 
} 

def m: (Integer => Unit) = 
    (x: Integer) => return (y: Integer) => 2 

उत्तर

16

औपचारिक रूप से बोल वापसी हमेशा निकटतम संलग्नित नामित विधि

A return expression return e must occur inside the body of some enclosing named method or function. The innermost enclosing named method or function in a source program, f , must have an explicitly declared result type, and the type of e must conform to it. The return expression evaluates the expression e and returns its value as the result of f . The evaluation of any statements or expressions following the return expression is omitted.

से लौट रहे तो यह एक लैम्ब्डा में विभिन्न अर्थ विज्ञान नहीं है के रूप में परिभाषित किया गया है। झुर्री यह है कि, एक सामान्य विधि के विपरीत, लैम्ब्डा से बनाए गए बंद होने से बंद करने की विधि में कॉल से बच सकते हैं और यदि आप इस तरह के बंद होने में वापसी करते हैं तो आप अपवाद प्राप्त कर सकते हैं।

If the return expression is itself part of an anonymous function, it is possible that the enclosing instance of f has already returned before the return expression is executed. In that case, the thrown scala.runtime.NonLocalReturnException will not be caught, and will propagate up the call stack.

अब, "क्यों" के लिए। एक कम कारण सौंदर्य है: भेड़ के बच्चे अभिव्यक्ति होते हैं और यह अच्छा होता है जब एक अभिव्यक्ति और उसके सभी उप-अभिव्यक्ति का अर्थ समान होता है चाहे घोंसले की संरचना क्या हो। नील Gafter http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html

मुख्य कारण यह मौजूद है, हालांकि, यह आपको सामान्य रूप से अनिवार्य प्रोग्रामिंग में उपयोग किए जाने वाले नियंत्रण प्रवाह के रूपों को आसानी से अनुकरण करने की अनुमति देता है लेकिन फिर भी आपको उच्च क्रम कार्यों में सार तत्वों की अनुमति देता है। एक खिलौना उदाहरण के रूप में, जावा का foreach निर्माण (for (x : xs) { yada; }) लूप के अंदर एक वापसी की अनुमति देता है। स्कैला में भाषा स्तर का पूर्वानुमान नहीं है। इसके बजाए, यह पुस्तकालय में foreach रखता है (उपज के बिना "अभिव्यक्ति के लिए" गिनती नहीं है क्योंकि वे सिर्फ foreach करने के लिए desugar)। गैर-स्थानीय रिटर्न होने का मतलब है कि आप जावा फोरैच ले सकते हैं और सीधे स्कैला फोरैच में अनुवाद कर सकते हैं।

बीटीडब्ल्यू, रूबी, स्मॉलटॉक, और आम लिस्प (मेरे सिर के ऊपर से) में भी समान "गैर-स्थानीय" रिटर्न होते हैं।

+0

क्या आपके पास कुछ और गंभीर उदाहरण हैं कि अर्थशास्त्र में अंतर क्यों आवश्यक है? चूंकि आपने जो सूचीबद्ध किया है, उसे आसानी से संशोधित 'foreach' के साथ अनुकरण किया जा सकता है जिसमें एक अनुमानित पैरामीटर है। – corazza

3

return कीवर्ड (वर्ग) के तरीकों के लिए आरक्षित है, यह काम करता है में इस्तेमाल नहीं किया जा सकता है। आप आसानी से परीक्षण कर सकते हैं कि:

object Foo { 
    val bar = (i: Int) => return i + i 
} 

इससे

<console>:42: error: return outside method definition 
     object Foo { val bar = (i: Int) => return i + i } 
             ^

अधिकतर आप तरीकों और कार्यों में एक ही रूप में है, क्योंकि समारोह के apply विधि व्यवहार के वाक्य रचना एक विधि बुला की तरह व्यवहार कर सकते हैं और तथाकथित ईटा-विस्तार एक विधि तर्क के रूप में पारित करने की अनुमति देता है।

इस मामले में, यह एक फर्क पड़ता है। जब विधि के रूप में परिभाषित करने, यह कानूनी है:

object Foo { 
    def bar(i: Int): Int = return i + i 
} 

सारांश में, आप केवल तरीकों कि सशर्त (प्रारंभिक) रिटर्न के लिए अनुमति देने में return उपयोग करना चाहिए। विधियों बनाम कार्यों पर चर्चा के लिए this post देखें।

+0

यह उत्तर वास्तव में उत्तर नहीं देता है * क्यों * यानी, उस निर्णय के पीछे भाषा डिजाइन तर्क। – corazza

+0

@jcz यह बेहद अस्पष्ट और अनजान हो जाएगा। लैम्बडास के बारे में सोचें, उदा। 'xs.foreach {x => अगर (x == y) x =' और वापस लौटें। –

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