反转 Scala 的未来
Invert a Scala Future
是否有可能 'invert' Scala 的未来?
有时 Future 的结果是成功意味着错误。在那种情况下,翻转 Future 会很好,即调用一个 returns Future 的函数,如果原始 Future 失败,它会以指定的值成功,如果原始 Future 成功,则失败并返回指定的错误。
def flip[T](original: Future[T])(value: => T)(error: Throwable): Future[T] = ???
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])
我认为您在 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
在 Scala 2.12 中,您将能够使用 transform
and 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!)
是否有可能 'invert' Scala 的未来?
有时 Future 的结果是成功意味着错误。在那种情况下,翻转 Future 会很好,即调用一个 returns Future 的函数,如果原始 Future 失败,它会以指定的值成功,如果原始 Future 成功,则失败并返回指定的错误。
def flip[T](original: Future[T])(value: => T)(error: Throwable): Future[T] = ???
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])
我认为您在 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
在 Scala 2.12 中,您将能够使用 transform
and 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!)