免责声明:下面的代码片段与正在进行的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
)- 如何处理故障?当其中一个输入
Futures
失败时,结果Future
对象看起来确实失败了
1)假设f是Future[T]
,然后写入
for {
t <- f
} yield List(t)
将把Future f的结果存储在t中,因此t的类型为t。收益率将其转化为List[t],用于理解的整体类型最终为Future[List[t]]。因此,理解的方法是从Futures
中提取Ts,用它们做点什么,然后把它们放回未来(好吧,我在这里简化了一点)。
它相当于
f.map(t => List(t))
2) 如果你的Future f包含一个Failure,那么for composition将只返回这个失败的Future,而不是执行yield。
一般来说,Scala中的理解只是糖,可以用map, flatMap, filter, foreach
重写。
我是一个会说英语的右撇子,所以通常我向左折叠,但折叠的每一步看起来都像:
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)
请注意,出现故障的版本存在短路。
请参阅ScalaDoc for flatMap以了解这两个信息。
编辑:我说得很谨慎,因为这是Coursera的作品,但更明确地说,这一要求没有得到满足:"返回的未来只有在fs
中的所有未来都完成后才能完成。"