2013-02-22 8 views
7

Ich mag wirklich scala.util.Try in Scala 2.10, und wie es mit Verständnis funktioniert macht die Handhabung mehrerer Schritte, die leicht schief gehen könnten.Schnelle Fehler bei der Verwendung für Verständnis mit scala.util.Try

Zum Beispiel könnten wir den folgenden Code verwenden, um sicherzustellen, dass wir diese zwei Zahlen nur dann und nur dann ausdrucken, wenn alles unter Kontrolle ist und wir den richtigen Wert erhalten.

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

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

Aber einer meiner Sorge ist, dass dieser Code alle Ausnahmen tatsächlich ignorieren, was bedeutet, es wird aussehen wie die folgende Try-cactch Block:

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

Soweit ich weiß, gibt es ein Argument, dass diese Art von Codes ist ein schlechter Geruch, denn niemand wird bemerken, dass es eine Ausnahme auftritt.

Was ich möchte, ist erreichen, dass nach wie vor for Verwendung sicherstellen, dass die println nur ausführen, wenn alles in Ordnung ist, aber wenn es eine Ausnahme in allen Schritten, wird es explodieren und direkt die Ausnahme werfen.

Derzeit hier ist, wie ich das tue, aber es scheint weniger elegant, weil es ein neues Try[Unit] Objekt vorstellen, also frage ich mich, wie könnte ich diesen Code besser machen?

Zum Beispiel ist es möglich, die result Variable und result.get Anweisung loszuwerden, aber immer noch Ausnahme geworfen werden?

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

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

aktualisiert

Um mehr klar zu machen, was ist es das Ergebnis von Scala REPL des ersten Codes in dieser Frage.

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> 

wir, dass nichts sehen können, geschieht hier, auch tryB ein Failure mit Ausnahme. Was ich möchte, ist eine Ausnahme geworfen wird, und ohne die Einführung der neuen Try[Unit] Objekt mit yield, ist das möglich?

+0

'println's Typ ist' Unit', also 'result' wird entweder eine Ausnahme auslösen oder den' Unit' Wert zurückgeben, '()'. –

+0

Nein, es wird keine Ausnahme ausgelöst, es sei denn, ich verwende die Methode "get". –

+0

Ihr Beispielcode enthält ein bedingungsloses 'result.get'. (Ich wollte "result.get" in meinen ersten Kommentar schreiben ...) –

Antwort

4

können Sie recover verwenden:

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 

ich die resNN entfernt, die Success(()) reflektiert.

+0

Ich versuche nicht, einen Standardwert zu erhalten oder eine Ausnahme zu retten. Stattdessen möchte ich, dass die Ausnahme direkt ausgelöst wird, wenn "tryEven" oder "tryEvenOrNeg1" ein Fehler ist. Mit anderen Worten, ich möchte den Effekt von "Ergebnis" erreichen.Get 'in meinem Post, aber ohne die' Ergebnis'-Variable. –

+0

'(für (a <- tryEven; b <- tryEven) Ausbeute println (s" Got $ a $ b ")). Get' –

0

OK, ich habe vergessen, wir haben immer implizite Konvertierung in Scala. ;-)

So könnten wir dieses Verhalten selbst implementieren, es wird mehr Objekt als die yield Version erstellen, aber ich denke, die Absicht dieses Codes ist viel klarer.

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

Es macht keinen Sinn,' Try' zu verwenden, wenn Sie eine Ausnahme auslösen. –

+1

Plus 'throwIfFailed' entspricht" Try's "get" Methode. –

Verwandte Themen