23

scala.util.Try と scala.concurrent.Future をチェーンすることは可能ですか? どちらも実質的に同じモナディック インターフェイスを提供しますが、それらをチェーンしようとするとコンパイル エラーが発生します。

例えば。以下の 2 つの署名があるとします。

def someFuture:Future[String] = ???
def processResult(value:String):Try[String] = ???

次のようなことは可能ですか?

val result = for( a <- someFuture; b <- processResult( a ) ) yield b;
result.map { /* Success Block */ } recover { /* Failure Block */ }

Future と Try を一緒に flatMapp することはできないため、これは明らかにコンパイル エラーになります。

ただし、それらをチェーンできるのは素晴らしい機能です-これはまったく可能ですか? それとも、それらを Future[Try[String]] に結合する必要がありますか?

(特に、将来または試行のいずれかで例外をキャッチするための単一の「回復」ブロックを持つことに興味があります)。

4

5 に答える 5

28

このような問題に直面した場合、理解のために異なる型を使用したい場合、1 つの解決策は、型の 1 つを選択して、もう 1 つの型をそれにマップすることです。あなたの状況では、先物の一意のプロパティ (非同期) を考えるFutureと、最小公分母として を選択し、 を にマップしTryますFuture。次のように簡単に実行できます。

val result = for{
  a <- someFuture
  b <- tryToFuture(processResult(a)) 
}  yield b
result.map { /* Success Block */ } recover { /* Failure Block */ }

def tryToFuture[T](t:Try[T]):Future[T] = {
  t match{
    case Success(s) => Future.successful(s)
    case Failure(ex) => Future.failed(ex)
  }
}

これが非常に一般的な状況であり、明示的な変換を常に追加する必要がない場合は、tryToFutureメソッドをヘルパー オブジェクトで暗黙的に定義し、次のように必要な場所にインポートできると思います。

object FutureHelpers{
  implicit def tryToFuture[T](t:Try[T]):Future[T] = {
    t match{
      case Success(s) => Future.successful(s)
      case Failure(ex) => Future.failed(ex)
    }
  }
}

import FutureHelpers._
val result = for{
  a <- someFuture
  b <- processResult(a) 
}  yield b
result.map { /* Success Block */ } recover { /* Failure Block */ }

Future.successandの呼び出しは、内部で別のタスクをサブミットするという点で、スコープ内にあるものFuture.failedすべてに影響を与えることを覚えておいてください。ExecutionContext

編集

Viktor がコメントで指摘したように、aTryを aに変換するプロセスは、以下の更新された例のようにFuture使用するだけでさらに簡単になります。Future.fromTry

val result = for{
  a <- someFuture
  b <- Future.fromTry(processResult(a)) 
}  yield b
result.map { /* Success Block */ } recover { /* Failure Block */ }

これはおそらく、暗黙的な処理を行ったり、独自の変換ロジックを展開したりするのと比較して、最善の策です。

于 2013-07-28T12:09:38.070 に答える
1
  implicit def convFuture[T](ft: Future[Try[T]]): Future[T] =
ft.flatMap {
  _ match {
    case Success(s) => Future.successful(s)
    case Failure(f) => Future.failed(f)
  }
}
于 2014-06-24T23:29:57.637 に答える
1

もあります

Future.fromTry(Try { ... })

だからあなたはできる

 val result = for {
   a <- someFuture
   b <- Future.fromTry(processResult(a)) 
 } yield b;
于 2016-08-25T14:48:34.867 に答える