我正在寻找一种方法来将任意长度的Futures列表转换为Future of List。我使用的是Playframework,所以最终,我真正想要的是一个Future[Result]
,但为了简化,我们就说Future[List[Int]]
。正常的方法是使用Future.sequence(...)
,但有一个扭曲...我给出的列表通常有大约10-20个Futures在里面。并且这些future中的一个失败并不罕见(它们正在发出外部Web服务请求)。
在其中一个失败的情况下,我不需要重试所有这些命令,而是希望能够找到成功的命令并返回它们。
例如,执行以下操作无效:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Success
import scala.util.Failure
val listOfFutures = Future.successful(1) :: Future.failed(new Exception("Failure")) ::
Future.successful(3) :: Nil
val futureOfList = Future.sequence(listOfFutures)
futureOfList onComplete {
case Success(x) => println("Success!!! " + x)
case Failure(ex) => println("Failed !!! " + ex)
}
scala> Failed !!! java.lang.Exception: Failure
我不想得到唯一的异常,我希望能够把1和3从那里拉出来。我尝试使用Future.fold
,但显然这只是在幕后调用Future.sequence
。
7条答案
按热度按时间fjaof16o1#
诀窍是首先确保没有一个future失败。
.recover
在这里是您的朋友,您可以将它与map
组合,将所有Future[T]
结果转换为Future[Try[T]]]
示例,所有这些示例都肯定是成功的future。Option
或Either
,但是如果您特别想要捕获异常,Try
是最干净的方法 *然后像前面一样使用
Future.sequence
,给予Future[List[Try[T]]]
然后过滤:
型
如果需要,您甚至可以提取特定的故障:
mbjcgjjk2#
Scala 2.12对
Future.transform
进行了改进,使其能够使用更少的代码。nhn9ugyo3#
我尝试了Kevin的答案,但在我的Scala版本(2.11.5)上遇到了一个小故障......我更正了这个问题,如果有人感兴趣,我还编写了一些额外的测试......以下是我的版本〉
1qczuiv04#
我刚刚遇到这个问题,并有另一个解决方案提供:
这里的想法是,在fold中,你等待列表中的下一个元素完成(使用for-comprehension语法),如果下一个元素失败,你就回退到你已经拥有的元素。
erhoui1w5#
您可以轻松地将将来的结果与选项 Package 在一起,然后展开列表:
wmtdaxz36#
您还可以在不同的列表中收集成功和不成功的结果:
eimct9ow7#
如果你因为某些原因需要保留失败的future,比如日志记录或条件处理,这可以在Scala 2.12+中使用,你可以在这里找到工作代码。