如何将Twitter未来[Map [A​​,Future [C]]]转换为未来[Map [A​​,C]]

时间:2013-12-03 20:13:56

标签: scala twitter map future finagle

我正在尝试解决以下问题:

我有一个未来[地图[A,B]]。对于所有B,我需要应用将B转换为Future [C]的方法,并且我想要回馈Future [Map [A​​,C]]

这是我到目前为止的代码:

def getClients(clientIds: Seq[Int]): Future[Map[Int, ClientData]] = {

  def getClientData(clientInfo: ClientInfo): Future[ClientData] = 
    clientInfo match {
      case ValidInfo(info) => getData(info)
      case _ => throw new Exception
    }

  client.getClients(clientIds) map {
    _.toMap map {
      case (clientId: Int, clientInfo: ClientInfo) =>
        getClientData(clientInfo) map {
          clientData => (clientId, clientData)
      }
    }
  }
}

此代码错误,因为它返回Iterable [Future [(Int,ClientData)]]

对于info getClients 是一个thrift方法,返回 Future [Map [A​​,B]] ,其中Map是可变的,所以我需要将它转换为不可变的首先使用toMap进行映射。

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:6)

scala> def f: Future[Map[String, Future[Int]]] = ???
f: Future[Map[String,Future[Int]]]

scala> def x = for {
     |   m <- f
     |   i = m.map{ case (k, fv) => fv.map{ k -> _ } }
     |   l <- Future.sequence(i)
     | } yield l.toMap
x: Future[Map[String,Int]]

一步一步:

Future[Map[A, Future[B]]]转换为Future[Iterable[Future[(A, B)]]]

scala> def x1 = f.map{ _.map{ case (k, fv) => fv.map{ k -> _ } } }
x1: Future[Iterable[Future[(String, Int)]]]

使用Iterable[Future[(A, B)]]Future[Iterable[(A, B)]]转换为flattenFuture[Future[...]] flatMap

scala> def x2 = x1.flatMap{ Future.sequence(_) }
x2: Future[immutable.Iterable[(String, Int)]]

Iterable[(A, B)]转换为Map[A, B]

scala> def x = x2.map{ _.toMap }
x: Future[Map[String,Int]]

对于com.twitter.util.Future,您应该在collect之前使用sequence代替toSeqcollect,因为它接受Seq

def x = for {
  m <- f
  i = m.map{ case (k, fv) => fv.map{ k -> _ } }
  l <- Future.collect(i.toSeq)
} yield l.toMap