[英]Dependent futures
Starting playing with Scala futures, I get stuck with dependent futures. 开始玩Scala期货,我陷入了依赖期货的困境。
Let's get a example. 我们来举个例子。 I search for places and get a
Future[Seq[Place]]
. 我搜索地点并获得
Future[Seq[Place]]
。 For each of theses places, I search for the closest subway stations (the service resurns a Future[List[Station]]
). 对于每个地方,我搜索最近的地铁站(该服务重新开始
Future[List[Station]]
)。
I would write this: 我会写这个:
Place.get()
.map { places =>
places.map { place =>
Station.closestFrom(place).map { stations =>
SearchResult(place, stations)
}
}
}
That thing will make me get a Future[Seq[Future[SearchResult]]]
... which is... not what I would have expected. 那件事会让我得到一个
Future[Seq[Future[SearchResult]]]
......这不是我所期待的。
What did I miss to get a Future[Seq[SearchResult]]
? 我错过了什么来获得
Future[Seq[SearchResult]]
?
Thanks for all, 谢谢大家,
Alban 阿尔班
You are missing two Future
concepts in your solution: flatMap
and Future.sequence
您在解决方案中缺少两个
Future
概念: flatMap
和Future.sequence
To explain each: 解释每个:
flatMap
is like map
except instead of giving it a function from future.map(A => B)
you give it a function from future.flatMap(A => Future[B])
. flatMap
就像map
一样,除了从future.map(A => B)
给它一个函数,你从future.flatMap(A => Future[B])
给它一个函数future.flatMap(A => Future[B])
。 This way you can chain Futures together. 这样你就可以将期货连在一起了。
Future.sequence
is a helper function that combines a list of futures to a future of a list: Seq[Future[A]] => Future[Seq[A]]
Future.sequence
是一个辅助函数,它将期货列表与列表的未来结合起来: Seq[Future[A]] => Future[Seq[A]]
Using these two features of the Future
API we can change your answer to be: 使用
Future
API的这两个功能,我们可以将您的答案更改为:
Place.get().flatMap { places =>
Future.sequence(places.map { place =>
Station.closestFrom(place).map { stations =>
SearchResult(place, stations)
}
})
}
Working with futures is generaly easier using for-comprehension rather than directly map/flatMap. 使用for-understand进行使用期望通常更容易,而不是直接映射/ flatMap。 In your situation it should look like this:
在你的情况下,它应该是这样的:
for {places <- Place.get()
searchResults <- Future.traverse(places)(place => for (stations <- Station.closestFrom(place))
yield SearchResult(place,stations)
)
} yield searchResults
Future
being a monad, it offers you several ways to chain your operations. Future
是一个单子,它为您提供了几种连接您的运营方式。
f : A => B
to what's inside the box myfuture : Future[A]
, indeed map
is the way to get a Future[B]
. f : A => B
到框内的myfuture : Future[A]
,确实是map
是获得Future[B]
。 But in the present situation Station.closestFrom
a does not give you a List[Stattion]
but a Future[List[Station]]
. Station.closestFrom
a没有给你一个List[Stattion]
而是一个Future[List[Station]]
。 h : A => Future[B]
or chain several of them (here Places.get
and Station.closestFrom
), flatMap
is the way to go. h : A => Future[B]
或链接其中几个(这里是Places.get
和Station.closestFrom
), flatMap
就是你要走的路。 Apply h
to a Future[A]
gives you a Future[B]
. h
应用于Future[A]
为您提供Future[B]
。 h : A => Future[B]
to a collection like a places : Seq[A]
, you should use Future.traverse : Seq[A] => (A => Future[B]) => Future[Seq[B]]
. h : A => Future[B]
到类似places : Seq[A]
的集合places : Seq[A]
,你应该使用Future.traverse : Seq[A] => (A => Future[B]) => Future[Seq[B]]
。 Furthermore, Scala's for-compresention is just syntactic sugar for flatMap/map so instead of writing complex code using those directly you can use a clean and clear for loop. 此外,Scala的for-compresention只是flatMap / map的语法糖,所以不用直接使用它们编写复杂的代码,你可以使用干净清晰的for循环。 The loop:
循环:
for { variable1 <- f1
variable2 <- f2
} yield expression
is equivalent to (without optimisations) : 相当于(没有优化):
f1.flatMap( variable1 => f2.map(variable2 => expression))
Don't hesitate to use for-comprehension, it really helps. 不要犹豫使用for-understanding,它确实有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.