2013-02-22 102 views
7

मुझे वास्तव में स्केल 2.10 में scala.util.Try पसंद है, और यह समझने के साथ कैसे काम करता है कई चरणों को संभालने में आसानी से गलत हो सकता है।scala.util के साथ समझने के लिए त्वरित विफलता।

उदाहरण के लिए, हम यह सुनिश्चित करने के लिए निम्न कोड का उपयोग कर सकते हैं कि हम केवल दो संख्याओं को प्रिंट करें यदि केवल और यदि सबकुछ नियंत्रण में है और हमें मूल्य सही तरीके से मिलता है।

def tryA: Try[Int] = {....} 
def tryB: Try[Int] = {....} 

for { 
    a <- tryA 
    b <- tryB 
} { 
    println (s"We got:${a+b}") 
} 

लेकिन मेरी चिंता यह है कि इस कोड को वास्तव में किसी भी अपवाद की अनदेखी कर रहा है, जिसका अर्थ है कि यह होगा निम्नलिखित कोशिश cactch ब्लॉक की तरह दिखता है:

try { 
    // ..... 
} catch { 
    case _: Exception => // Swallow any exception 
} 

जहाँ तक मुझे पता है, वहाँ है एक तर्क है कि इस तरह के कोड खराब गंध है, क्योंकि कोई भी नोटिस नहीं करेगा कि एक अपवाद होता है।

मैं क्या प्राप्त करने के लिए चाहते हैं कि अभी भी for का उपयोग कर यकीन है कि अगर सब कुछ ठीक है println केवल निष्पादित, लेकिन अगर कोई चरणों में किसी भी अपवाद नहीं है, यह उड़ा और सीधे अपवाद बाहर फेंक होगा बनाना है।

वर्तमान में यह है कि मैं यह कैसे करता हूं, लेकिन यह कम सुरुचिपूर्ण लगता है क्योंकि यह एक नया Try[Unit] ऑब्जेक्ट पेश करता है, इसलिए मैं सोच रहा हूं कि मैं यह कोड कैसे बेहतर बना सकता हूं?

उदाहरण के लिए, result चर और result.get कथन से छुटकारा पाने के लिए संभव है, लेकिन फिर भी अपवाद को फेंक दिया जा सकता है?

def tryA: Try[Int] = {....} 
def tryB: Try[Int] = {....} 

val result = for { 
    a <- tryA 
    b <- tryB 
} yield { 
    println (s"We got:${a+b}") 
} 
result.get 

अद्यतन

बात को और अधिक स्पष्ट करने के लिए, यह इस प्रश्न के पहले कोड की स्काला आरईपीएल से परिणाम है।

scala> def tryA: Try[Int] = Success(1) 
tryA: scala.util.Try[Int] 

scala> def tryB: Try[Int] = Failure(new Exception("error")) 
tryB: scala.util.Try[Int] 

scala> for { 
    | a <- tryA 
    | b <- tryB 
    | } { 
    | println (s"We got:${a+b}") 
    | } 

scala> 

हम कि कुछ भी नहीं देख सकते हैं यहां होता, यहां तक ​​कि tryB अपवाद के साथ एक Failure है। मैं जो प्राप्त करना चाहता हूं वह एक अपवाद फेंक दिया गया है, और नए Try[Unit] ऑब्जेक्ट को yield के साथ पेश किए बिना, क्या यह संभव है?

+0

'println' का प्रकार' यूनिट 'है, इसलिए' परिणाम 'या तो अपवाद फेंक देगा या' यूनिट 'मान, '()' वापस करेगा। –

+0

नहीं, यह तब तक अपवाद नहीं फेंक देगा जब तक कि मैं 'get' विधि का उपयोग नहीं करता। –

+0

आपके नमूना कोड में बिना शर्त 'result.get' शामिल है। (मेरा पहला टिप्पणी में 'result.get' लिखना था ...) –

उत्तर

4

आप recover उपयोग कर सकते हैं:

import scala.util.Try 

def tryEven = Try { val i = (math.random * 1000).toInt; if (i % 2 != 0) throw new Exception("odd") else i } 

def tryEvenOrNeg1 = Try { val i = (math.random * 1000).toInt; if (i % 2 != 0) throw new Exception("odd") else i } recover { case exx: Exception => -1 } 

scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b") 
res1: scala.util.Try[Unit] = Failure(java.lang.Exception: odd) 

scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b") 
res2: scala.util.Try[Unit] = Failure(java.lang.Exception: odd) 

scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b") 
res3: scala.util.Try[Unit] = Failure(java.lang.Exception: odd) 

scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b") 
Got 542, -1 

scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b") 
res5: scala.util.Try[Unit] = Failure(java.lang.Exception: odd) 

scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b") 
res6: scala.util.Try[Unit] = Failure(java.lang.Exception: odd) 

scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b") 
Got 692, 750 

मैं resNN कि Success(()) परिलक्षित हटा दिया।

+0

मैं जो करने का प्रयास कर रहा हूं वह डिफ़ॉल्ट मान प्राप्त करने या अपवाद को बचाने के लिए नहीं है। इसके बजाय, मैं चाहता हूं कि 'tryEven' या' tryEvenOrNeg1' विफल होने पर अपवाद को सीधे फेंक दिया जाए। दूसरे शब्दों में, मैं 'परिणाम के प्रभाव को प्राप्त करना चाहता हूं।मेरी पोस्ट में 'प्राप्त करें, लेकिन' परिणाम 'चर के बिना। –

+0

'(के लिए (एक <- tryEven; बी <- tryEven) उपज println (एस" $ एक $ बी "मिला))। –

0

ठीक है, मैं भूल गया कि हम हमेशा स्कैला में निहित रूपांतरण करते हैं। ;-)

इसलिए हम इस व्यवहार को स्वयं लागू कर सकते हैं, यह yield संस्करण से अधिक ऑब्जेक्ट बनाएगा, लेकिन मुझे लगता है कि इस कोड का इरादा बहुत स्पष्ट है।

implicit class BlowUpTry[T](current: Try[T]) { 

    def throwIfFailed: Try[T] = current match { 
    case Success(value)  => current 
    case Failure(exception) => throw exception 
    } 

} 

def tryA: Try[Int] = Success(1) 
def tryB: Try[Int] = Failure(new Exception("error")) 

for { 
    a <- tryA.throwIfFailed 
    b <- tryB.throwIfFailed 
} { 
    println(s"We got ${a + b}") 
} 
+5

प्राप्त करें यदि आप अपवाद फेंकने जा रहे हैं तो 'Try' का उपयोग करने में कोई बात नहीं है। –

+1

प्लस 'throwIfFailed'' try' की "get" विधि के बराबर है। –