我有一个功能,需要期货Future[A]*
,我希望它返回Future[List[A]]
。
def singleFuture[T](futures: List[Future[A]]): Future[List[A]] = {
val p = Promise[T]
futures filter { _ onComplete { case x => p complete x /*????*/ } }
p.future
}
我还希望类型Future[List[A]]
的结果未来在列表期货List[Future[A]]
完成后立即完成。
该代码不起作用。我想我应该在这里使用flatMap
因为应该有2个内部循环:一个用于未来,一个用于promise。但是如何?
我不想在这里使用进行理解,因为我想更深入地理解这个过程。
答案 0 :(得分:8)
这已经为你实现了:
def singleFuture[T](futures: List[Future[A]]): Future[List[A]] = Future.sequence(futures)
当然,您可以查看序列的实现:
def sequence[A, M[_] <: TraversableOnce[_]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = {
in.foldLeft(Promise.successful(cbf(in)).future) {
(fr, fa) => for (r <- fr; a <- fa.asInstanceOf[Future[A]]) yield (r += a)
} map (_.result())
}
如果你只想处理列表,而不是任何有foldLeft的东西,这可以简化:
def sequence[A](in: List[Future[A]]): Future[List[A]] = {
in.foldRight[Future[List[A]](Promise.successful(Nil) {
(fa, fr) => for { r <- fr; a <- fa } yield (a :: r)
}
}
答案 1 :(得分:3)
您可以使用foldRight来实现此目的:
def singleFuture[A](futures: List[Future[A]]): Future[List[A]] = {
val p = Promise[List[A]]()
p.success(List.empty[A])
val f = p.future // a future containing empty list.
futures.foldRight(f) {
(fut, accum) => // foldRight means accumulator is on right.
for {
list <- accum; // take List[A] out of Future[List[A]]
a <- fut // take A out of Future[A]
}
yield (a :: list) // A :: List[A]
}
}
如果期货清单中的任何未来失败,&lt; - fut将失败,导致将被设置为未来失败。
如果您想避免使用for,可以将其扩展为flatMap,如下所示:
accum.flatMap( list => fut.map(a => a :: list))
或者您可以使用async-await(注意它仍然是一个实验性功能)。
def singleFuture[T](futures: List[Future[T]]): Future[List[T]] = async {
var localFutures = futures
val result = ListBuffer[T]()
while (localFutures != Nil) {
result += await { localFutures.head }
localFutures = localFutures.tail
}
result.toList
}