在使用返回选项未来的函数进行映射后展平选项的未来

时间:2016-03-16 13:49:30

标签: scala

我有一个Future[Option[String]]类型的集合,我将它映射到一个返回Future[Option[Profile]]的函数,但这会创建一个Future[Option[Future[Option[Profile]]]]的返回类型,因为queryProfile返回类型是`未来[选项[简介]]'

val users: Future[Option[User]] = someQuery
val email: Future[Option[String]] = users map(opSL => opSL map(_.email) )
val userProfile = email map {opE => opE map {E => queryProfile(E)}}

我需要使用Profile内部包含的val userProfile对象而不解压所有这些级别,使用flatMap或“flatten”的正确方法是什么,或者是否有更好地接近所有人?

3 个答案:

答案 0 :(得分:4)

您可以通过以下方式获得“部分未来”:

  val maybeProfile: Future[Profile] = users
    .collect { case Some(u) => u.email }
    .flatMap { email => queryProfile(email) }
    .collect { case Some(p) => p }

现在maybeProfile包含(完全“裸”/未包装)Profile实例,但前提是它能够找到它。你可以.map像往常一样用它来做其他事情,这将以通常的方式工作。

如果您想要阻止并等待完成,您将不得不在某个时刻处理丢失的案例。例如:

   val optionalProfile: Option[Profile] = Await.result(
     maybeProfile
       .map { p => Some(p) } // Or just skip the last `collect` above
       .recover { case _:NoSuchElementException => None },
     1 seconds
   )

如果您对Future[Option[Profile]]感到满意,并且更愿意拥有“展开”魔法,并且处理丢失的案例本地化在一个地方,您可以将上面的两个片段放在一起,如下所示:< / p>

val maybeProfile: Future[Option[Profile]] = users 
  .collect { case Some(u) => u.email }
  .flatMap { email => queryProfile(email) }
  .recover { case _:NoSuchElementException => None }

或者像建议的其他答案一样使用Option.fold

val maybeProfile: Future[Option[Profile]] = users
    .map { _.map(_.email) }
    .flatMap { _.fold[Future[Option[Profile]]](Future.successful(None))(queryProfile) }

就个人而言,我发现最后一个选项的可读性较差。

答案 1 :(得分:0)

就我个人而言,我认为像scalaz /猫提供的OptionT这样的monad变换器将是最干净的方法:

val users = OptionT[Future,User](someQuery)
def queryProfile(email:String) : OptionT[Future,Profile] = ...
for {
  u <- users
  p <- queryProfile(u.email)
} yield p

答案 2 :(得分:0)

我只是创建一个这样的辅助方法:

private def resolveProfile(optEmail: Option[String]): Future[Option[Profile] =
  optEmail.fold(Future.successful(None)) { email =>
    queryProfile(email).map(Some(_))
  }

然后您可以flatMap原来的email未来:

val userProfile = email.flatMap(resolveProfile)