开始玩Scala期货,我陷入了依赖期货的困境。
让我们举个例子。我搜索地点并获得Future[Seq[Place]]
。对于每个地方,我搜索最近的地铁站(服务重新发现Future[List[Station]]
)。
我会这样写:
Place.get()
.map { places =>
places.map { place =>
Station.closestFrom(place).map { stations =>
SearchResult(place, stations)
}
}
}
那件事会让我得到Future[Seq[Future[SearchResult]]]
......这不是我所期望的。
我错过了Future[Seq[SearchResult]]
?
谢谢大家,
阿尔
答案 0 :(得分:6)
您的解决方案中缺少两个Future
概念:flatMap
和Future.sequence
解释每一个:
flatMap
与map
类似,但不是从future.map(A => B)
给它一个函数,而是从future.flatMap(A => Future[B])
给它一个函数。通过这种方式,您可以将期货连在一起。
Future.sequence
是一个帮助函数,它将未来列表与列表的未来结合起来:Seq[Future[A]] => Future[Seq[A]]
使用Future
API的这两个功能,我们可以将您的答案更改为:
Place.get().flatMap { places =>
Future.sequence(places.map { place =>
Station.closestFrom(place).map { stations =>
SearchResult(place, stations)
}
})
}
答案 1 :(得分:2)
使用for-understanding进行使用期望通常比使用for-understandnce更容易,而不是直接映射/ flatMap。在你的情况下它应该是这样的:
for {places <- Place.get()
searchResults <- Future.traverse(places)(place => for (stations <- Station.closestFrom(place))
yield SearchResult(place,stations)
)
} yield searchResults
Future
是一个monad,它为您提供了几种连接操作的方法。
f : A => B
到myfuture : Future[A]
框内的内容,确实是map
是获得Future[B]
的方法。但在目前的情况下,Station.closestFrom
a不会为您提供List[Stattion]
,而是Future[List[Station]]
。h : A => Future[B]
或链接其中的一些(Places.get
和Station.closestFrom
),flatMap
就可以了。将h
应用于Future[A]
会为您提供Future[B]
。h : A => Future[B]
应用于places : Seq[A]
这样的集合,则应使用Future.traverse : Seq[A] => (A => Future[B]) => Future[Seq[B]]
。此外,Scala的for-compresention只是flatMap / map的语法糖,所以不用直接使用它们编写复杂的代码,你可以使用干净清晰的for循环。循环:
for { variable1 <- f1
variable2 <- f2
} yield expression
相当于(没有优化):
f1.flatMap( variable1 => f2.map(variable2 => expression))
不要犹豫使用理解,这确实有帮助。