如何将结果Future [Option [T]]组合成Seq [T]

时间:2017-07-19 16:44:06

标签: scala sequence future option

我有一个方法

 def readTree(id: String): Future[Option[CategoryTreeResponse]]

以及字符串channels:List[String]的列表。

如何迭代并将所有结果组合成非未来序列?,例如:

 def readAllTrees(): Seq[CategoryTreeResponse] =  ???

可能没有阻挡。

来自势在必行的世界,我会这样做:

import scala.concurrent.duration._

def readTrees(): Seq[CategoryTreeResponse] = {
  val list = ListBuffer[CategoryTreeResponse]()
  for (id <- channels) {
    val tree = Await.result(readTree(id), 5.seconds)
    if (tree.isDefined) {
      list += tree.get
    }
  }
  list
}

2 个答案:

答案 0 :(得分:1)

你可以做这样的事情

def readAllTrees(channels: List[String]): Future[Seq[CategoryTreeResponse]] = {
    Future.sequence(channels.map(readTree(_))).map(_.flatten)
}

我更改了readAllTrees的签名以接收列表并返回序列的未来。

如果要访问生成的序列,则需要等到完成

 Await.result(readAllTrees(channels), Duration.Inf)

但这不是管理期货的好方法,因为它会锁定调用Await的线程。已经

答案 1 :(得分:1)

Future.sequence和Await.result应该有所帮助。我同意Mikel,尽管使用Future类的map / flatMap / foreach等方法尽可能保持异步更好

scala> :paste
// Entering paste mode (ctrl-D to finish)

import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

case class CategoryTreeResponse()

val futureResults: List[Future[Option[CategoryTreeResponse]]] = List(
 Future.successful(Option(CategoryTreeResponse())), 
 Future.successful(Option(CategoryTreeResponse())), 
 Future.successful(None)
) 
val futureResult: Future[List[Option[CategoryTreeResponse]]] = Future.sequence(futureResults)
val allResults: List[Option[CategoryTreeResponse]] = Await.result(futureResult, Duration.Inf)
val nonEmptyResults: Seq[CategoryTreeResponse] = allResults.flatMap(_.toSeq)

// Exiting paste mode, now interpreting.

import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
defined class CategoryTreeResponse
futureResults: List[scala.concurrent.Future[Option[CategoryTreeResponse]]] = List(Future(Success(Some(CategoryTreeResponse()))), Future(Success(Some(CategoryTreeResponse()))), Future(Success(None)))
futureResult: scala.concurrent.Future[List[Option[CategoryTreeResponse]]] = Future(Success(List(Some(CategoryTreeResponse()), Some(CategoryTreeResponse()), None)))
allResults: List[Option[CategoryTreeResponse]] = List(Some(CategoryTreeResponse()), Some(CategoryTreeResponse()), None)
nonEmptyResults: Seq[CategoryTreeResponse] = List(CategoryTreeResponse(), CategoryTreeResponse())

scala>