为成功和失败绘制未来

时间:2014-04-13 14:03:18

标签: scala

我有一个Future [T],我希望在成功和失败方面映射结果。

例如,

val future = ... // Future[T]
val mapped = future.mapAll { 
  case Success(a) => "OK"
  case Failure(e) => "KO"
}

如果我使用mapflatmap,则只会映射成功期货。如果我使用recover,它只会映射失败的期货。 onComplete执行回调但不返回修改后的未来。 Transform会起作用,但需要2个函数而不是部分函数,​​所以有点丑陋。

我知道我可以制作一个新的Promise,并使用onCompleteonSuccess / onFailure完成该操作,但我希望有一些我遗漏的内容请允许我用一个PF来完成上述操作。

4 个答案:

答案 0 :(得分:38)

编辑2017-09-18:从Scala 2.12开始,有transform方法需要Try[T] => Try[S]。所以你可以写

val future = ... // Future[T]
val mapped = future.transform {
  case Success(_) => Success("OK")
  case Failure(_) => Success("KO")
}

对于2.11.x,以下仍然适用:

AFAIK,你不能用一个PF直接做到这一点。并transform转换Throwable =>可以扔,所以这也无济于事。最接近你可以开箱即用:

val mapped: Future[String] = future.map(_ => "OK").recover{case _ => "KO"}

那就是说,实现你的mapAll是微不足道的:

implicit class RichFuture[T](f: Future[T]) {
  def mapAll[U](pf: PartialFunction[Try[T], U]): Future[U] = {
    val p = Promise[U]()
    f.onComplete(r => p.complete(Try(pf(r))))
    p.future
  }
}

答案 1 :(得分:3)

在第一步中,您可以执行以下操作:

import scala.util.{Try,Success,Failure}

val g = future.map( Success(_):Try[T] ).recover{
  case t => Failure(t)
}.map {
  case Success(s) => ...
  case Failure(t) => ...
}

其中T是未来结果的类型。然后,您可以使用隐式转换将Future特征添加到此结构作为新方法:

implicit class MyRichFuture[T]( fut: Future[T] ) {
  def mapAll[U]( f: PartialFunction[Try[T],U] )( implicit ec: ExecutionContext ): Future[U] = 
    fut.map( Success(_):Try[T] ).recover{
      case t => Failure(t)
    }.map( f )
 }

实现了您正在寻找的语法:

val future = Future{ 2 / 0 }
future.mapAll {
  case Success(i) => i + 0.5
  case Failure(_) => 0.0
}

答案 2 :(得分:3)

map和flatMap变体:

implicit class FutureExtensions[T](f: Future[T]) {
  def mapAll[Target](m: Try[T] => Target)(implicit ec: ExecutionContext): Future[Target] = {
    val p = Promise[Target]()
    f.onComplete { r => p success m(r) }(ec)
    promise.future
  }

  def flatMapAll[Target](m: Try[T] => Future[Target])(implicit ec: ExecutionContext): Future[Target] = {
    val promise = Promise[Target]()
    f.onComplete { r => m(r).onComplete { z => promise complete z }(ec) }(ec)
    promise.future
  }
}

答案 3 :(得分:3)

Scala 2.12以来,您可以使用transform来映射这两种情况:

future.transform {
      case Success(_) => Try("OK")
      case Failure(_) => Try("KO")
}

如果您更喜欢使用transformWith而不是Future,那么您还有Try。查看documentation了解详情。