【问题标题】:Map a Future for both Success and Failure为成功和失败绘制未来
【发布时间】:2014-05-27 10:39:31
【问题描述】:

我有一个 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。

【问题讨论】:

    标签: scala future


    【解决方案1】:

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

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

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

    AFAIK,你不能用一个 PF 直接做到这一点。而transform 转换 Throwable => 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
      }
    }
    

    【讨论】:

    • 是的,我可以很容易地写出来,只是想知道类似的东西是否潜伏在某个地方。
    • 嗨@espenhw,在你回答的第二段中,你的意思是val mapped: Future[String] = future.map(_ => "OK").recover{case _ => "KO")
    • 不知道使用哪个组合器让我发疯——尤其是因为 .onComplete 具有我想要的签名,但它并没有给我一个新的未来。我将使用此解决方案;谢谢。
    • 问题是 .map 可能会失败,并且您会错误地恢复它(从某种意义上说,我们只想从最初的未来中恢复)。
    • 我们可以使用作为 Scala 2.12 的一部分引入的新 transform 方法来更新这个答案吗?
    【解决方案2】:

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

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

    如果您更喜欢使用Future 而不是Try,您还可以使用transformWith。详情请查看documentation

    【讨论】:

      【解决方案3】:

      map 和 flatMap 变体:

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

      【讨论】:

        【解决方案4】:

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

        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
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多