基于成功的结果失败的未来

问题描述 投票:4回答:3

我的代码中有一个场景,我需要根据包含特定值的成功结果使Future失败。我可以通过flatMap使这项工作很好,但我想知道是否有一种更清洁的方法来使这项工作。首先,一个非常简单的例子:

import concurrent._

case class Result(successful:Boolean)
object FutureTest {
  def main(args: Array[String]) {
    import ExecutionContext.Implicits._

    val f = Future{Result(false)}.flatMap{ result =>
      result match{
        case Result(false) => Promise.failed(new Exception("The call failed!!")).future
        case _ => Promise.successful(result).future
      }
    }

    f onFailure{
      case x => println(x.getMessage())
    }
  }
}

所以在我的例子中,如果返回的Future的成功指标值为Result,我希望false失败。正如我所提到的,我可以使用flatMap使这项工作正常,但我希望消除的代码行是:

case _ => Promise.successful(result).future

这句话似乎没必要。我想要的行为是能够定义条件,如果它的计算结果为true,那么允许我像我一样返回一个不同的Future,但是如果不是这样,那就把事情保留原样(有点像PartialFunction)有没有办法做到这一点,我只是没有看到?我看过collecttransform,那些看起来也不合适。

编辑

在从@Rex Kerr和@ senia获得map建议后,我创建了一个PimpedFuture和一个隐式转换,使代码有点像这样:

class PimpedFuture[T](f:Future[T])(implicit ex:ExecutionContext){
  def failWhen(pf:PartialFunction[T,Throwable]):Future[T] = {
    f map{
      case x if (pf.isDefinedAt(x)) => throw pf(x)
      case x => x
    }
  }
}

隐含的

  implicit def futToPimpedFut[T](fut:Future[T])(implicit ec:ExecutionContext):PimpedFuture[T] = new PimpedFuture(fut)

和新的处理代码:

val f = Future{ Result(false) } failWhen {
  case Result(false) => new Exception("The call failed!!")
}

我认为这仍然是一个更清洁,同时仍然使用建议使用map

scala future
3个回答
7
投票

你可以用map轻松完成这项工作:

val f = Future{ Result(false) } map {
  case Result(false) => throw new Exception("The call failed!!")
  case x => x
}

但你仍然需要明确提到你正在传递身份。

请注意,在这种情况下,你should not使用andThenandThen用于副作用,而不是用于改变结果(与同名的Function1方法不同)。


0
投票

还有一个不同的解决方案(没有堆栈跟踪副作用,因为@cmbaxter提到)

val prom = Promise[Int]()
val f = future {
    1
}

f onComplete {
    case Success(i) if i < 5 => prom.failure(new RuntimeException("_ < 5"))
    case Success(x) => prom.success(x)
}

prom.future onComplete {
    case Success(s) => println(s"We cool '$s'")
    case Failure(th) => println(s"All failed, ${th.getMessage}")
}

0
投票

最干净的解决方案是调用filter方法,如评论中提到的@senia。

Future { Result(false) }.filter(_.successful) // throws NoSuchElementException

如果您想要一个不同的异常类型,可以使用recoverWith链接调用:

Future { Result(false) }.filter(_.successful).recoverWith {
  case _: NoSuchElementException => Future.failed(new Exception("The call failed!!"))
}
© www.soinside.com 2019 - 2024. All rights reserved.