获得未来[List [Future [T]]]但需要Future [List [T]](richment patttern)

时间:2018-04-25 12:23:10

标签: scala

链接到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玩,但是无法编译。它也觉得这是一种非常常见的情况,但今天一直没有任何结果。实质上:

  • 获得n个对象的未来
  • 拨打第二项服务
  • 使用组合值(浓缩)返回n个对象的未来

2 个答案:

答案 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你将删除一个未来。

相关问题