web-dev-qa-db-ja.com

未来を待ち、どちらかを受け取る

scala futureが失敗した可能性があります。Await.resultを使用すると例外がスローされます。代わりにf: Future[String]があればメソッドAwait.resultOpt(f): Option[String]が必要です。またはAwait.resultEither(f): Either[String]

scala.util.control.Exception.catchingを使用してこれを取得することも、f map (Right(_)) recover { case t: Throwable => Left(t) }を使用することもできますが、もっと簡単な方法が必要です。

27
schmmd

Await.readyを使用して、Futureが成功または失敗するまで単にブロックし、そのFutureへの参照を返します。

そこから、おそらくOption[Try[T]]であるFutureのvalueを取得したいと思うでしょう。 Await.ready呼び出しのため、valueSomeであると想定しても安全です。そして、それはTry[T]Either[Throwable, T]の間のマッピングの問題です。

ショートバージョン:

val f: Future[T] = ...

val result: Try[T] = Await.ready(f, Duration.Inf).value.get

val resultEither = result match {
  case Success(t) => Right(t)
  case Failure(e) => Left(e)
}
59
Dylan

APIを宣伝するための短いバージョン:

scala> val f = Future(7)
f: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@13965637

scala> f.value.get
res0: scala.util.Try[Int] = Success(7)

scala> import scala.util._
import scala.util._

scala> Either.cond(res0.isSuccess, res0.get, res0.failed.get)
res2: scala.util.Either[Throwable,Int] = Right(7)

scala> val f = Future[Int](???)
f: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@64c4c1

scala> val v = f.value.get
v: scala.util.Try[Int] = Failure(Java.util.concurrent.ExecutionException: Boxed Error)

scala> Either.cond(v.isSuccess, v.get, v.failed.get)
res4: scala.util.Either[Throwable,Int] = Left(Java.util.concurrent.ExecutionException: Boxed Error)

ワンライナーであることにはわずかな利点があります。

しかし、もちろん、.toEither拡張メソッドの場合、何行かかったかは気にしません。

3
som-snytt

あなたはあなた自身のタイプユーティリティを作り始め、そのようなことをすることができます

  trait RichTypes {

    import scala.util.{Try, Success, Failure}
    import scala.concurrent.{Await, Future}
    import scala.concurrent.duration.Duration

    implicit class RichFuture[T](f: Future[T]) {
      def awaitResult(d: Duration): Either[Throwable, T] = {
        Try(Await.result(f, d)).toEither
      }
    }

    implicit class RichTry[T](tri: Try[T]) {
      def toEither(): Either[Throwable, T] = {
        tri.fold[Either[Throwable, T]](Left(_), Right(_))
      }
    }
  }

  object Example
    extends App
      with RichTypes {

    import scala.concurrent.Future
    import scala.concurrent.duration._

    val succ = Future.successful("hi").awaitResult(5.seconds)
    val fail = Future.failed(new Exception("x")).awaitResult(5.seconds)

    println(succ) // Right(hi)
    println(fail) // Left(Exception(x))
  }

Tryにも.foldが含まれるように分離しました:)。

1
Rhys Bradbury