स्काला में वापसी


84

मैं एक नौसिखिया स्काला प्रोग्रामर हूं और एक अजीब व्यवहार के साथ आया हूं।

def balanceMain(elem: List[Char]): Boolean =
  {
    if (elem.isEmpty)
      if (count == 0)
        true;
      else false;

    if (elem.head == '(')
      balanceMain(elem.tail, open, count + 1);....

मूल रूप से ऊपर मैं सच लौटना चाहता हूं अगर elem.isEmptyऔर count == 0। अन्यथा, मैं झूठे लौटना चाहता हूं।

अब ऊपर मैंने पढ़ा है कि scala में रिटर्न स्टेटमेंट जोड़ने की कोई आवश्यकता नहीं है। इसलिए मैंने returnऊपर छोड़ दिया है। लेकिन यह बूलियन वापस नहीं करता है। अगर मैं रिटर्न स्टेटमेंट जोड़ूं return true। यह पूरी तरह से काम करता है। ऐसा क्यों है?

इसके अलावा, यह क्यों माना जाता है कि स्कैला में बयान वापस करना एक बुरा व्यवहार है


2
जब तक आप अपने कोड को छोटे पर्याप्त तरीकों से तोड़ते हैं, तब तक आमतौर पर रिटर्न कीवर्ड की कोई आवश्यकता नहीं होती है।
मौहिज

@ मौहिज़ धन्यवाद क्या आप इसे समझा सकते हैं? तुम वह कैसे करोगे।
जतिन

4
ऐसा लगता है जैसे आप कॉर्सेला स्कैला कोर्स ले रहे हैं। ऑल द बेस्ट :)
वीमा

जवाबों:


139

यह उतना आसान नहीं है जितना कि returnकीवर्ड को छोड़ना । स्काला में, यदि कोई नहीं है, returnतो अंतिम मान रिटर्न मान लिया जाता है। इसलिए, यदि अंतिम अभिव्यक्ति वही है जो आप वापस करना चाहते हैं, तो आप returnकीवर्ड को छोड़ सकते हैं । लेकिन अगर आप जो लौटना चाहते हैं वह अंतिम अभिव्यक्ति नहीं है, तो स्काला को पता नहीं चलेगा कि आप उसे वापस करना चाहते हैं

एक उदाहरण:

def f() = {
  if (something)
    "A"
  else
    "B"
}

यहाँ फ़ंक्शन fका अंतिम एक्सप्रेशन एक if / else अभिव्यक्ति है जो एक स्ट्रिंग का मूल्यांकन करता है। चूंकि कोई स्पष्ट रूप से returnचिह्नित नहीं है, स्काला यह अनुमान लगाएगा कि आप इस परिणाम को वापस करना चाहते हैं यदि / अन्यथा अभिव्यक्ति: एक स्ट्रिंग।

अब, अगर हम if / else अभिव्यक्ति के बाद कुछ जोड़ते हैं :

def f() = {
  if (something)
    "A"
  else
    "B"

  if (somethingElse)
    1
  else
    2
}

अब अंतिम अभिव्यक्ति एक if / else अभिव्यक्ति है जो किसी Int का मूल्यांकन करती है। तो वापसी का प्रकार fइंट होगा। यदि हम वास्तव में चाहते थे कि स्ट्रिंग वापस आ जाए, तो हम मुश्किल में हैं क्योंकि स्काला को इस बात का कोई पता नहीं है कि हमारा क्या इरादा है। इस प्रकार, हमें या तो स्ट्रिंग को एक चर में संग्रहीत करके इसे ठीक करना होगा और इसे दूसरी / अगर अभिव्यक्ति के बाद वापस करना होगा, या क्रम को बदलना होगा ताकि स्ट्रिंग भाग अंतिम हो जाए।

अंत में, हम returnएक नेस्टेड के साथ भी कीवर्ड से बच सकते हैं, अगर आपकी तरह और भी अभिव्यक्ति:

def f() = {
  if(somethingFirst) {
    if (something)      // Last expression of `if` returns a String
     "A"
    else
     "B"
  }
  else {
    if (somethingElse)
      1
    else
      2

    "C"                // Last expression of `else` returns a String
  }

}


4
सभी देवताओं द्वारा, धन्यवाद! मैं घंटों तक एक ही समस्या से लड़ रहा था (कोर्ससेरा में भी कोर्स कर रहा था) और यह समझने में सक्षम नहीं था कि वापसी की आवश्यकता क्यों थी।
इगोर रोड्रिगेज

पहले उदाहरण के लिए, यदि आप रिटर्न जोड़ते हैं तो क्या होता है। यानी return "A"और return "B"?
सामको

@ T.Rex यह "A" या "B" मान के साथ f () के कॉलर पर वापस आ जाएगा। लेकिन जैसा कि मैंने अपने जवाब में समझाया। स्काला में कभी भी रिटर्न का उपयोग न करें। यदि स्काला में कथन क्रियात्मक तरीके से काम करते हैं। वे एक प्रकार से किसी चीज का मूल्यांकन करते हैं। जावा में ternary ऑपरेटर की तरह (? :)। उदाहरण: वैल फू = अगर (मायबूल) "ए" और "बी" - फू एक स्ट्रिंग होगा जिसमें "ए" या "बी" होगा। इसी तरह एक फंक्शन के बारे में सोचें जो कुछ नहीं लौटाता है लेकिन उसमें अंतिम अभिव्यक्ति के मूल्य का मूल्यांकन करता है।
Grmpfhmbl

23

यह विषय वास्तव में थोड़ा अधिक जटिल है जैसा कि अब तक के उत्तरों में वर्णित है। रोब नॉरिस का यह ब्लॉगपोस्ट इसे और अधिक विस्तार से बताता है और रिटर्न का उपयोग करते समय उदाहरण देता है कि वास्तव में आपका कोड टूट जाएगा (या कम से कम गैर-स्पष्ट प्रभाव होगा)।

इस बिंदु पर मुझे केवल पोस्ट का सार उद्धृत करना चाहिए। सबसे महत्वपूर्ण कथन शुरुआत में सही है। इसे एक पोस्टर के रूप में प्रिंट करें और इसे अपनी दीवार पर डालें :-)

returnकीवर्ड "वैकल्पिक" या "निष्कर्ष निकाला" नहीं है; यह आपके प्रोग्राम का अर्थ बदल देता है, और आपको इसका उपयोग कभी नहीं करना चाहिए।

यह एक उदाहरण देता है, जहां यह वास्तव में कुछ तोड़ता है, जब आप किसी फ़ंक्शन को इनलाइन करते हैं

// Inline add and addR
def sum(ns: Int*): Int = ns.foldLeft(0)((n, m) => n + m) // inlined add

scala> sum(33, 42, 99)
res2: Int = 174 // alright

def sumR(ns: Int*): Int = ns.foldLeft(0)((n, m) => return n + m) // inlined addR

scala> sumR(33, 42, 99)
res3: Int = 33 // um.

चूंकि

एक returnअभिव्यक्ति, जब मूल्यांकन किया जाता है, वर्तमान गणना को छोड़ देता है और उस विधि के कॉलर पर वापस लौटता है जिसमें returnदिखाई देता है।

यह लिंक्ड पोस्ट में दिए गए उदाहरणों में से केवल एक है और इसे समझना सबसे आसान है। वहाँ अधिक हैं और मैं आपको प्रोत्साहित करता हूं कि आप वहां जाएं, पढ़ें और समझें।

जब आप जावा जैसी अनिवार्य भाषाओं से आते हैं, तो यह पहली बार में अजीब लग सकता है, लेकिन एक बार जब आप इस शैली के अभ्यस्त हो जाएंगे तो यह समझ में आएगा। मुझे एक और उद्धरण के साथ बंद करें:

यदि आप खुद को ऐसी स्थिति में पाते हैं, जहां आपको लगता है कि आप जल्दी लौटना चाहते हैं, तो आपको उस तरीके पर फिर से विचार करने की जरूरत है, जिस तरह से आपने अपनी गणना को परिभाषित किया है।


12
मैं रोब से सहमत नहीं हूं, IMO आप returnकेवल लैम्ब्डा एक्सप्रेशन में उपयोग नहीं करना चाहिए , लेकिन यह भाषा में एक चमकदार डिजाइन विकल्प है, कोड को भी संकलन नहीं करना चाहिए (अजगर में यह lambdaवापसी विवरण के बिना कीवर्ड होने से बचा जाता है )। .. एक दूसरे के मामलों में मैं का उपयोग करने में एक वास्तविक समस्या नहीं दिख रहा है returnकि आप मान वापस करना चाहते (और हाँ विधि निष्पादन से बाहर निकलने के वजह से है क्या वापसी सभी भाषाओं में के लिए प्रयोग किया जाता है!)
daveoncode

2
आप अपनी राय रखने के लिए स्वतंत्र हैं, लेकिन बहुत से लोग इस बात से सहमत हैं कि स्काला में वापसी का उपयोग करना कम से कम बुरी शैली है। मैं आपको आधिकारिक स्काला डॉक उदाहरण खोजने की हिम्मत करता हूं जो रिटर्न का उपयोग करते हैं। यह AFAIK आधिकारिक डॉक्स में भी नहीं समझाया गया है, केवल कल्पना दस्तावेज़ में (अध्याय 6.20)। खुद मार्टिन ओडस्की को उद्धृत करने के लिए (स्काला में प्रोग्रामिंग) "तरीकों के लिए अनुशंसित शैली वास्तव में स्पष्ट होने से बचने के लिए है, और विशेष रूप से कई, वापसी बयान। इसके बजाय, प्रत्येक विधि को एक मूल्य के रूप में एक अभिव्यक्ति के रूप में सोचें, जो वापस आ गई है।" इस पुस्तक का पहला संस्करण मुफ्त ऑनलाइन उपलब्ध है artima.com/pins1ed
Grmpfhmbl

4

मैं स्काला का कार्यक्रम नहीं करता, लेकिन मैं निहित प्रतिफल (रूबी) के साथ एक और भाषा का उपयोग करता हूं। आपके पास अपने if (elem.isEmpty)ब्लॉक के बाद कोड है - कोड की अंतिम पंक्ति वही है जो वापस आ गई है, यही कारण है कि आपको वह नहीं मिल रहा है जिसकी आप अपेक्षा कर रहे हैं।

संपादित करें: यहाँ अपने कार्य को लिखने का एक सरल तरीका है। बस isEmpty के बूलियन मूल्य का उपयोग करें और स्वचालित रूप से सही या गलत वापस करने के लिए गणना करें:

def balanceMain(elem: List[Char]): Boolean =
{
    elem.isEmpty && count == 0
}

धन्यवाद। लेकिन मैं केवल तभी लौटना चाहता हूं जब elem.isEmpty && count == 0 सच सही रूप से ब्लॉक जारी रखें। ऊपर वाला भले ही झूठ हो, वापस आ जाएगा।
जतिन

@ जतिन: आह, एहसास नहीं हुआ। explicitइस मामले में शुरुआती और वापसी उचित होगी।
jmdeldin

@Frank: न ही इसे ओपी कोड में परिभाषित किया गया है। मैंने मान लिया कि यह एक विधि कॉल था।
jmdeldin

4

ifएक इसी के बिना बयान मत लिखो else। एक बार जब आप elseअपने टुकड़े को जोड़ते हैं तो आप देखेंगे कि आपके trueऔर falseवास्तव में फ़ंक्शन के अंतिम भाव हैं।

def balanceMain(elem: List[Char]): Boolean =
  {
    if (elem.isEmpty)
      if (count == 0)
        true
      else
        false
    else
      if (elem.head == '(')
        balanceMain(elem.tail, open, count + 1)
      else....

6
मैंने इसे लागू किया, 3 नेस्टेड आईएफ मिला और यह बदसूरत लग रहा है। क्या इसे अच्छा बनाने के लिए कोई पैटर्न है?
Capacytron

4

डिफ़ॉल्ट रूप से किसी फ़ंक्शन की अंतिम अभिव्यक्ति वापस आ जाएगी। आपके उदाहरण में बिंदु के बाद एक और अभिव्यक्ति है, जहां आप अपना रिटर्न मान चाहते हैं। यदि आप अपनी अंतिम अभिव्यक्ति से पहले कुछ भी वापस करना चाहते हैं, तो आपको अभी भी उपयोग करना है return

आप इस तरह से अपने उदाहरण को संशोधित कर सकते हैं, Booleanपहले भाग से वापस आने के लिए

def balanceMain(elem: List[Char]): Boolean = {
  if (elem.isEmpty) {
    // == is a Boolean resulting function as well, so your can write it this way
    count == 0
  } else {
    // keep the rest in this block, the last value will be returned as well
    if (elem.head == "(") {
      balanceMain(elem.tail, open, count + 1)
    }
    // some more statements
    ...
    // just don't forget your Boolean in the end
    someBoolExpression
  }
}

9
"कथन" नहीं। "अभिव्यक्ति"
विक्टर क्लैंग

0

जल्दी वापसी के उद्देश्य के लिए केस मैच का उपयोग करें। यह आपको सभी रिटर्न शाखाओं को स्पष्ट रूप से घोषित करने के लिए मजबूर करेगा, जिससे कहीं न कहीं लिखने की भूल करने की लापरवाह गलती को रोका जा सके।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.