使用返回期权未来的函数进行映射后展平期权的未来

Ins*_*Bot 3 scala

我有一个类型集合,Future[Option[String]]并将其映射到一个返回的函数Future[Option[Profile]],但这会创建一个返回类型,Future[Option[Future[Option[Profile]]]]因为queryProfile返回类型为`Future [Option [Profile]]

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)}}
Run Code Online (Sandbox Code Playgroud)

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

Dim*_*ima 5

您可以使用以下内容获得“部分未来”:

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

现在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
   )
Run Code Online (Sandbox Code Playgroud)

如果您对拥有感到满意Future[Option[Profile]],并且希望拥有“解包”魔术,并且将丢失的案例定位在一个地方,则可以将上面的两个片段放在一起,如下所示:

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

或使用Option.fold类似建议的其他答案:

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

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