Map a Future for both Success and Failure

后端 未结 4 2043
闹比i
闹比i 2021-01-30 22:38

I have a Future[T] and I want to map the result, on both success and failure.

Eg, something like

val future = ... // Future[T]
val mapped = future.mapAll         


        
相关标签:
4条回答
  • 2021-01-30 22:50

    Edit 2017-09-18: As of Scala 2.12, there is a transform method that takes a Try[T] => Try[S]. So you can write

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

    For 2.11.x, the below still applies:

    AFAIK, you can't do this directly with a single PF. And transform transforms Throwable => Throwable, so that won't help you either. The closest you can get out of the box:

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

    That said, implementing your mapAll is trivial:

    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
      }
    }
    
    0 讨论(0)
  • 2021-01-30 22:50

    In a first step, you could do something like:

    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) => ...
    }
    

    where T is the type of the future result. Then you can use an implicit conversion to add this structure the Future trait as a new method:

    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 )
     }
    

    which implements the syntax your are looking for:

    val future = Future{ 2 / 0 }
    future.mapAll {
      case Success(i) => i + 0.5
      case Failure(_) => 0.0
    }
    
    0 讨论(0)
  • 2021-01-30 23:02

    Both map and flatMap variants:

    implicit class FutureExtensions[T](f: Future[T]) {
      def mapAll[Target](m: Try[T] => Target)(implicit ec: ExecutionContext): Future[Target] = {
        val promise = Promise[Target]()
        f.onComplete { r => promise 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
      }
    }
    
    0 讨论(0)
  • 2021-01-30 23:06

    Since Scala 2.12 you can use transform to map both cases:

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

    You also have transformWith if you prefer to use a Future instead of a Try. Check the documentation for details.

    0 讨论(0)
提交回复
热议问题