2013-02-22 7 views
7

Scala 2.10ではscala.util.Tryが本当に好きですが、for-comprehensionでどのように動作して複数のステップを処理しやすくなります。scala.util.Tryとの補完を使用するとすぐにエラーが発生する

たとえば、次のコードを使用して、すべてが制御され、正しく値が取得された場合にのみ、2つの数値を出力することができます。

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

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

しかし、私の懸念の一つ、このコードは実際には以下のtry-cactchのブロックのように見えることを意味している、すべての例外を無視していることである。私の知る限りでは

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

を、そこにあります誰も例外が発生していることに気付かないので、この種のコードは悪い匂いであるという主張です。

私が達成したいのは、まだforを使用して、すべてがOKであれば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のREPLからの結果です。

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'の型が' Unit'なので、 'result'は例外を投げたり、' Unit'値 '()'を返します。 –

+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 

私はSuccess(())を反映resNNを削除しました。

+0

私がやっていることは、デフォルト値を取得したり、例外を救済したりすることではありません。代わりに、 'tryEven'または' tryEvenOrNeg1'が失敗の場合、例外をただスローするだけです。言い換えれば、私は '結果の効果を達成したいと思います。私の投稿では 'result'変数なしで' get'を実行します。 –

+0

'(a < - tryEven; b < - tryEven)yield println(s" Got $ a $ b "))。get' –

0

私は常にScalaで暗黙の変換を行っていることを忘れています。 ;-)

私たちは自分自身でこの動作を実装することができるので、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

例外をスローする場合は、「試行」を使用する意味はありません。 –

+1

プラス 'throwIfFailed'は' Try'の "get"メソッドと同じです。 –

関連する問題