8

私は Scala 2.10 をとても気に入っscala.util.Tryています。それが for-comprehension とどのように機能するかにより、簡単に失敗する可能性のある複数のステップを処理できます。

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

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

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

しかし、私の懸念の 1 つは、このコードが実際にはすべての例外を無視していることです。つまり、次の try-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 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は、Failurewith 例外であっても何も起こらないことがわかります。私が取得したいのは、例外がスローされることです.新しいTry[Unit]オブジェクトを導入することなく、yieldこれは可能ですか?

4

2 に答える 2

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(())

于 2013-02-22T02:39:21.583 に答える
0

OK、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}")
}
于 2013-02-22T03:31:14.750 に答える