如何将Future[Option[Future[Option[X]]]]转换为Future[Option[X]]?
如果是TraversableOnce而不是Option,我会使用未来伴侣对象;但是选项呢?
示例:
def processAndReturnFuture(x:String):Future[String] = future(x)
def processAgainAndReturnOption(x:String):Option[String] = Some(x)
val futOpt:Future[Option[String]] = future(Some("x"))
val futOptFutOpt:Future[Option[Future[Option[String]]]] =
futOpt.map( opt =>
opt.map( x =>
processAndReturnFuture(x).map( processedX =>
processAgainAndReturnOption(processedX)
)
)
)发布于 2013-10-18 11:43:07
更新答复
这也许能起作用。我所做的是用最外层的map上的flatMap和最外层的Option上的模式匹配替换前两个Future调用。
val futOptFutOpt: Future[Option[String]] =
futOpt.flatMap {
case None => Future.successful(None)
case Some(x) =>
processAndReturnFuture(x).map {
processedX => processAgainAndReturnOption(processedX)
}
}初始答案
在您的代码中,我假设您有一个map调用,该调用将Future[Option[A]]转换为Future[Option[Future[Option[X]]]]。将该map替换为flatMap,并在结果中删除最顶层的Option层。你最终会和Future[Option[X]]在一起。我的意思是:
scala> import scala.concurrent._
import scala.concurrent._
scala> import ExecutionContext.Implicits.global
import ExecutionContext.Implicits.global
scala> val f1: Future[Option[Future[Option[String]]]] =
| Future.successful(Some(1)).map(v => Some(Future.successful(Some(v.toString))))
f1: scala.concurrent.Future[Option[scala.concurrent.Future[Option[String]]]] = scala.concurrent.impl.Promise$DefaultPromise@6f900132
scala> val f2: Future[Option[String]] =
| Future.successful(Some(1)).flatMap(v => Future.successful(Some(v.toString)))
f2: scala.concurrent.Future[Option[String]] = scala.concurrent.impl.Promise$DefaultPromise@2fac9a62对于您的实际上下文,我可能不完全正确,但是您可能会通过将一些map替换为几个flatMap来解决这个问题。
发布于 2016-09-30 17:59:20
如果您使用的是scalaZ或猫,则可以使用更通用的方法,这将适用于更多类型( Future需要有Traverse类型,而Option只需要是Monad)
第一条路是:
import scalaz.std.scalaFuture.futureInstance
import scalaz.std.option.optionInstance
import scalaz.syntax.traverse._
val fofo: Future[Option[Future[Option[Int]]]] = Future(Option(Future(Option(5))))
val ffoo: Future[Future[Option[Option[Int]]]] = fofo.map(_.sequence)
val fo = fofo.map(_.sequence).join.map(_.join) // Future(Some(5))在这里,您首先使用sequence在将来“交换”类型,然后将它们连接在一起。因此,对于任何两个更高级的类型,F[_]和G[_],其中F -有一个Traverse实例,而G是一个Monad -您可以这样做。将Future更改为List,实现不会更改。
另一种方法,这可能是有趣的-是使用单一变压器。想法是,在Monad中,您可以将类型连接在一起,F[F[A]] => F[A]。
Future(Future(4)).join // Future(4)
Option(Option(3)).join // Option(3)
List(List(1, 2)).join // List(1, 2)如果在此上下文中将Future[Option]视为F类型,则可以将它们连接在一起!您所需要的只是显示FutureOption是一个单曲。ScalaZ有一个单体转换器(从较小的单体中“合成”或组装更大的单体的方法)。
import scalaz.OptionT.optionT
val FOT = OptionT.optionTMonadPlus[Future] //creating monad transformer on top of Option
val fo2 = FOT.join(optionT(fofo.map(_.map(optionT(_))))).run // Future(Some(5))optionT将一个Future[Option]放在一个单曲中,所以我们需要做两次--一个用于外部Future[Option],另一个用于内部Future[Option]。
这种方法适用于任何类型的F[G[FG],其中您有一个Monad转换器。
我们还可以让它变得更好,避免在Future中出现两个丑陋的Future。地图来自Functor类型,它们是可组合的!因此,我们可以在它上组装我们的新Functor[Future[Option]]和map:
val FOT = OptionT.optionTMonadPlus[Future]
val FOF = Functor[Future].compose[Option]
val fo2 = FOT.join(optionT(FOF.map(fofo)(optionT(_)))).run发布于 2016-08-05 13:11:16
以下是我对此事的看法:
val futOptFutOpt: Future[Option[String]] =
futOpt.map(_.toSeq)
.flatMap(Future.traverse(_)(processAndReturnFuture))
.map(_.headOption)这基本上就是
futOpt从Future[Option]转换为Future[Seq]Seq处理processAndReturnFuture的每个元素,并返回一个新的Future[Seq]Future[Seq]转换回Future[Option]https://stackoverflow.com/questions/19448779
复制相似问题