免责声明:以下代码段与正在进行的Coursera课程之一相关。 我们认为它只是出于学习目的而发布,不应该用于提交作为家庭作业的解决方案。
正如下面的评论所述,我们需要将Futures列表转换为列表的单个Future。更重要的是,如果至少有一个输入期货失败,那么最终的未来就会失败。
我遇到了以下实施,我完全不明白。
/** Given a list of futures `fs`, returns the future holding the list of values of all the futures from `fs`.
* The returned future is completed only once all of the futures in `fs` have been completed.
* The values in the list are in the same order as corresponding futures `fs`.
* If any of the futures `fs` fails, the resulting future also fails.
*/
def all[T](fs: List[Future[T]]): Future[List[T]] =
fs.foldRight(Future(Nil:List[T]))((f, fs2) =>
for {
x <- f
xs <- fs2
} yield (x::xs))
特别是,我不了解其中的下一步:
Future[T] -> T
转换发生在哪里?看起来xs <- fs2
是我们触及初始Futures
的唯一地方,xs
类型中的每一个都应为Future[T]
(但不知何故,它变为T
)。 Future
失败时,看起来生成的Futures
对象会失败。 答案 0 :(得分:6)
1)假设f是Future[T]
,然后写
for {
t <- f
} yield List(t)
将Future f的结果存储在t中 - 因此t为T类型。yield将其转换为List [T],整个for-comprehension的类型最终为Future [List [T] ]。因此,理解是从Futures
中提取你的Ts,用它们做一些事情,然后把它们放回未来(好的,我在这里简化一点)。
相当于
f.map(t => List(t))
2)如果你的未来f包含失败,那么for-comprehension将只返回失败的Future而不是执行yield。
总的来说,Scala中的for-comprehension只是可以用map, flatMap, filter, foreach
重写的糖。
答案 1 :(得分:2)
我是说英语的右撇子,所以通常我会弃左,但折叠的每一步都是这样的:
Fn flatMap ((x: T) => Fs map (xs => x :: xs))
您的值为x
。
该功能适用于成功,这解释了为什么失败会让你感到寒冷:
scala> timed(Await.ready(all(List(Future{Thread sleep 5*1000; 1},Future(2),Future{Thread sleep 10*1000; 3})), Duration.Inf))
res0: (Long, scala.concurrent.Awaitable[List[Int]]) = (10002419021,scala.concurrent.impl.Promise$DefaultPromise@2a8025a0)
scala> timed(Await.ready(all(List(Future{Thread sleep 5*1000; 1},Future(???),Future{Thread sleep 10*1000; 3})), Duration.Inf))
res1: (Long, scala.concurrent.Awaitable[List[Int]]) = (5000880298,scala.concurrent.impl.Promise$DefaultPromise@3750d517)
请注意,故障版本会短路。
有关这两位信息,请参阅有关flatMap的ScalaDoc。
编辑:我说的很谨慎,因为这是Coursera的工作,但更明显的是,这个要求没有得到满足:“只有在fs
的所有期货都已完成后,才会完成返回的未来。”