反转Scala未来

时间:2015-08-03 21:16:48

标签: scala future

是否可以“反转”Scala Future?

有时,未来成功的结果意味着错误。在这种情况下,翻转一个Future是很好的,即调用一个返回Future的函数,如果原始Future失败则该函数以指定值成功,如果原始Future成功则失败并返回指定的错误。

def flip[T](original: Future[T])(value: => T)(error: Throwable): Future[T] = ???

3 个答案:

答案 0 :(得分:8)

  def craziness[A](future: Future[A])(default : => A)(error: Throwable)(implicit ec: ExecutionContext): Future[A] = {
    val p = Promise[A]()
    import scala.util.{Success, Failure, Try}
    future.onComplete {
      case _: Success[_] => p.failure(error)
      case _: Failure[_] => p.complete(Try(default))
    }
    p.future
  }

这是一个显示工作的repl会话:

scala> val f1 = craziness[String](Future("hello!"))("my crazy default")(new Throwable("boom"))
f1: scala.concurrent.Future[String] = scala.concurrent.impl.Promise$DefaultPromise@4d154ccd

scala> f1 onComplete { println }
Failure(java.lang.Throwable: boom)

scala> val f2 = craziness[String](Future(throw new Exception("boom!")))("my crazy default")(new Throwable("boom"))
f2: scala.concurrent.Future[String] = scala.concurrent.impl.Promise$DefaultPromise@1890516e

scala> f2 onComplete { println }
Success(my crazy default)

编辑:

为了完整性,def craziness[A](future: Future[A])应该是def craziness[A](future: => Future[A])

答案 1 :(得分:1)

我认为你是在recoverrecoverWith构建之后。这是一个快速的REPL会话,以显示其用法。

$ scala
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scala.concurrent.Future
import scala.concurrent.Future

scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global

scala> val failFuture = Future(sys.error("BOOM"))
failFuture: scala.concurrent.Future[Nothing] = scala.concurrent.impl.Promise$DefaultPromise@6e06451e

scala> val defaultValue = 100
defaultValue: Int = 100

scala> val futureRecoveredWithDefaultFuture = failFuture.recoverWith { case e: RuntimeException => Future.successful(defaultValue) }
futureRecoveredWithDefaultFuture: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@130161f7

scala> val futureRecoveredWithDefaultValue = failFuture.recover { case e: RuntimeException => defaultValue }
futureRecoveredWithDefaultValue: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@3b69e7d1

检查这是否真的有效:

scala> import scala.concurrent.duration._
import scala.concurrent.duration._

scala> import scala.concurrent.Await
import scala.concurrent.Await

scala> val res1 = Await.result(futureRecoveredWithDefaultFuture, 1.second)
res1: Int = 100

scala> val res2 = Await.result(futureRecoveredWithDefaultValue, 1.second)
res2: Int = 100

答案 2 :(得分:0)

在Scala 2.12中,您可以使用transformtransformWith来实现此目标。

但在此之前,这应该会让你到那里:

implicit class InvertFuture[T](val fut: Future[T]) extends AnyVal {
  def flip(recover: Throwable => T)(fail: T => Throwable)(implicit ec: ExecutionContext): Future[T] =
        fut.recover({ case t => recover(t) }).map(t => throw fail(t))
}

// And usage:

scala> Future(1).flip(_ => 2)(_ => throw new IllegalStateException("ohnoes!")) onComplete println
Failure(java.lang.IllegalStateException: ohnoes!)