是否可以“反转”Scala Future?
有时,未来成功的结果意味着错误。在这种情况下,翻转一个Future是很好的,即调用一个返回Future的函数,如果原始Future失败则该函数以指定值成功,如果原始Future成功则失败并返回指定的错误。
def flip[T](original: Future[T])(value: => T)(error: Throwable): Future[T] = ???
答案 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)
我认为你是在recover
和recoverWith
构建之后。这是一个快速的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中,您可以使用transform
和transformWith
来实现此目标。
但在此之前,这应该会让你到那里:
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!)