मेरी पहली पसंद आम तौर पर पुनरावृत्ति का उपयोग करना होगा। यह केवल मध्यम रूप से कम कॉम्पैक्ट है, संभवतः तेज है (निश्चित रूप से धीमी नहीं), और प्रारंभिक समाप्ति में तर्क को अधिक स्पष्ट कर सकता है। इस मामले में आपको नेस्टेड डिस्टेंस की जरूरत है जो थोड़ा अजीब है:
def sumEvenNumbers(nums: Iterable[Int]) = {
def sumEven(it: Iterator[Int], n: Int): Option[Int] = {
if (it.hasNext) {
val x = it.next
if ((x % 2) == 0) sumEven(it, n+x) else None
}
else Some(n)
}
sumEven(nums.iterator, 0)
}
मेरी दूसरी पसंद का उपयोग करना होगा return
, क्योंकि यह सब कुछ और बरकरार रखता है और आपको केवल तह को लपेटने की आवश्यकता होती है def
ताकि आपके पास वापस लौटने के लिए कुछ हो - इस मामले में, आपके पास पहले से ही एक विधि है, इसलिए:
def sumEvenNumbers(nums: Iterable[Int]): Option[Int] = {
Some(nums.foldLeft(0){ (n,x) =>
if ((n % 2) != 0) return None
n+x
})
}
जो इस मामले में पुनरावृत्ति की तुलना में बहुत अधिक कॉम्पैक्ट है (हालांकि हम पुनरावृत्ति के साथ विशेष रूप से अशुभ हो गए क्योंकि हमें एक पुनरावृत्ति / पुनरावृत्ति परिवर्तन करना पड़ा)। उछल नियंत्रण प्रवाह से बचने के लिए कुछ है जब बाकी सब समान है, लेकिन यहां यह नहीं है। उन मामलों में इसका उपयोग करने में कोई नुकसान नहीं है जहां यह मूल्यवान है।
अगर मैं अक्सर ऐसा कर रहा था और इसे कहीं एक विधि के बीच में चाहता था (तो मैं सिर्फ रिटर्न का उपयोग नहीं कर सकता था), मैं शायद गैर-स्थानीय नियंत्रण प्रवाह उत्पन्न करने के लिए अपवाद-हैंडलिंग का उपयोग करूंगा। यही है, आखिरकार, यह क्या अच्छा है, और त्रुटि से निपटने का एकमात्र समय उपयोगी नहीं है। एकमात्र ट्रिक स्टैक ट्रेस उत्पन्न करने से बचने के लिए है (जो वास्तव में धीमा है), और यह आसान है क्योंकि विशेषता NoStackTrace
और उसके बच्चे के लक्षण ControlThrowable
आपके लिए पहले से ही ऐसा करते हैं। स्काला पहले से ही आंतरिक रूप से इसका उपयोग करता है (वास्तव में, यही कारण है कि यह गुना के अंदर से वापसी को लागू करता है!)। चलो अपना बनाते हैं (नेस्टेड नहीं किया जा सकता है, हालांकि कोई इसे ठीक कर सकता है):
import scala.util.control.ControlThrowable
case class Returned[A](value: A) extends ControlThrowable {}
def shortcut[A](a: => A) = try { a } catch { case Returned(v) => v }
def sumEvenNumbers(nums: Iterable[Int]) = shortcut{
Option(nums.foldLeft(0){ (n,x) =>
if ((x % 2) != 0) throw Returned(None)
n+x
})
}
यहाँ बेशक उपयोग return
करना बेहतर है, लेकिन ध्यान दें कि आप shortcut
कहीं भी डाल सकते हैं , न कि पूरी विधि को लपेटकर।
मेरे लिए अगली पंक्ति में गुना को फिर से लागू करना होगा (या तो खुद को या ऐसा पुस्तकालय खोजने के लिए जो ऐसा करता है) ताकि यह जल्दी समाप्ति का संकेत दे सके। ऐसा करने के दो प्राकृतिक तरीके मूल्य को प्रचारित नहीं करना है, लेकिन एक Option
मूल्य है, जहां None
समाप्ति को दर्शाता है; या एक दूसरे संकेतक फ़ंक्शन का उपयोग करने के लिए जो सिग्नल को पूरा करता है। किम स्टेबेल द्वारा दिखाया गया स्लैज़ आलसी फोल्ड पहले से ही पहले मामले को कवर करता है, इसलिए मैं दूसरा (एक परस्पर कार्यान्वयन के साथ) दिखाऊंगा:
def foldOrFail[A,B](it: Iterable[A])(zero: B)(fail: A => Boolean)(f: (B,A) => B): Option[B] = {
val ii = it.iterator
var b = zero
while (ii.hasNext) {
val x = ii.next
if (fail(x)) return None
b = f(b,x)
}
Some(b)
}
def sumEvenNumbers(nums: Iterable[Int]) = foldOrFail(nums)(0)(_ % 2 != 0)(_ + _)
(चाहे आप पुनरावृत्ति, वापसी, आलस्य, आदि द्वारा समाप्ति को लागू करते हैं, आप पर निर्भर है।)
मुझे लगता है कि मुख्य उचित वेरिएंट को कवर करता है; कुछ अन्य विकल्प भी हैं, लेकिन मुझे यकीन नहीं है कि कोई इस मामले में उनका उपयोग क्यों करेगा। ( Iterator
खुद अच्छा काम करेगा अगर यह एक था findOrPrevious
, लेकिन यह नहीं है, और अतिरिक्त काम यह करने के लिए हाथ से करता है कि यह यहाँ उपयोग करने के लिए एक मूर्खतापूर्ण विकल्प बनाता है।)