首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >“未来[选择[未来[Option[X]”进入“未来[Option[X]]”

“未来[选择[未来[Option[X]”进入“未来[Option[X]]”
EN

Stack Overflow用户
提问于 2013-10-18 11:38:44
回答 4查看 2.6K关注 0票数 5

如何将Future[Option[Future[Option[X]]]]转换为Future[Option[X]]

如果是TraversableOnce而不是Option,我会使用未来伴侣对象;但是选项呢?

示例:

代码语言:javascript
复制
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)
      )
    )
  )
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-10-18 11:43:07

更新答复

这也许能起作用。我所做的是用最外层的map上的flatMap和最外层的Option上的模式匹配替换前两个Future调用。

代码语言:javascript
复制
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]]在一起。我的意思是:

代码语言:javascript
复制
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来解决这个问题。

票数 7
EN

Stack Overflow用户

发布于 2016-09-30 17:59:20

如果您使用的是scalaZ,则可以使用更通用的方法,这将适用于更多类型( Future需要有Traverse类型,而Option只需要是Monad)

第一条路是:

代码语言:javascript
复制
  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]

代码语言:javascript
复制
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有一个单体转换器(从较小的单体中“合成”或组装更大的单体的方法)。

代码语言:javascript
复制
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

代码语言:javascript
复制
val FOT = OptionT.optionTMonadPlus[Future]
val FOF = Functor[Future].compose[Option]
val fo2 = FOT.join(optionT(FOF.map(fofo)(optionT(_)))).run
票数 4
EN

Stack Overflow用户

发布于 2016-08-05 13:11:16

以下是我对此事的看法:

代码语言:javascript
复制
val futOptFutOpt: Future[Option[String]] =
  futOpt.map(_.toSeq)
    .flatMap(Future.traverse(_)(processAndReturnFuture))
    .map(_.headOption)

这基本上就是

  1. futOptFuture[Option]转换为Future[Seq]
  2. 使用Seq处理processAndReturnFuture的每个元素,并返回一个新的Future[Seq]
  3. Future[Seq]转换回Future[Option]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19448779

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档