我有一个Future [T],我希望在成功和失败方面映射结果。
例如,
val future = ... // Future[T]
val mapped = future.mapAll {
case Success(a) => "OK"
case Failure(e) => "KO"
}
如果我使用map
或flatmap
,则只会映射成功期货。如果我使用recover
,它只会映射失败的期货。 onComplete
执行回调但不返回修改后的未来。 Transform
会起作用,但需要2个函数而不是部分函数,所以有点丑陋。
我知道我可以制作一个新的Promise
,并使用onComplete
或onSuccess
/ onFailure
完成该操作,但我希望有一些我遗漏的内容请允许我用一个PF来完成上述操作。
答案 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了解详情。