链接到scastie
上的实时代码我正在发送一个http请求,返回Future[List[Post]]
。这些帖子中的每一个都包含一个id(someId
),我需要使用第二个服务来解析它。此服务返回Future[String]
。我将使用此已解析的值与原始Post
一起构建Result
对象。
我在akka http服务器内部并向这些其他后端服务发出请求。所以我想返回一个Future[List[Result]]
,但到目前为止,我一直遇到Future[List[Future[Result]]]
(代码也感觉不干净)
case class Post(t: String, someId: Int)
case class Result(t: String, resolved: String)
def resolveId(id: Int) : Future[String] = Future(s"$id")
val f = Future(List(Post("a",1),Post("b",1), Post("c",2)))
val result: Future[List[Future[Result]]] = for {
l <- f
} yield for {
e <- l
} yield for {
r <- resolveId(e.someId)
} yield Result(e.t, r)
//val neededResult : Future[List[Result]] =
我一直在努力学习,并且每次都在flatMap
玩,但是无法编译。它也觉得这是一种非常常见的情况,但今天一直没有任何结果。实质上:
答案 0 :(得分:2)
使用Future.sequence
Future.sequence
方法需要List[Future[T]]
并将其转换为Future[List[T]]
:
val f = Future(List(Post("a",1),Post("b",1), Post("c",2)))
val neededResult : Future[List[Result]] =
for {
l <- f
tupL <- Future sequence (l map (post => resolveId(post.someId).map(s => post.t -> s)))
} yield {
tupL map Result.apply.tupled
}
或者,以描述性形式:
val neededResult =
f.flatMap(l => Future sequence (l map (post => resolveId(post.someId).map(s => post.t -> s))))
.map(_ map Result.apply.tupled)
答案 1 :(得分:2)
如果您对函数式编程和Cats感兴趣,您还可以使用遍历(或序列)。
import cats.implicits._
case class Post(t: String, someId: Int)
case class Result(t: String, resolved: String)
val f: Future[List[Future[Post]]] = Future(List(Future(Post("a", 1)), Future(Post("b", 1)), Future(Post("c", 2))))
val result: Future[List[Post]] = f.flatMap(_.traverse(identity))
Traverse与Future.sequence + map基本相同,但它适用于任何Applicative(不仅适用于未来)。然后你有一个Future [Future [List [Post]]和flatMap你将删除一个未来。