如何处理在理解中返回期权的期货

时间:2015-12-16 02:06:06

标签: scala future

我的服务正在返回Future [Option [Entity]],我目前正在这样做:

val user = userService.getById(1)
val company = userService.getById(1)

if(user.get.companyId == company.get.id) {
   save(...)

   if(...) {
      blahService.boo();   
   }

   return ...
} else 
{
  ...
  return ...
}

现在,如果我将其重构为for-comprehension,我该如何处理else子句?我是否从for-comp返回一些东西,然后像其他'那样使用它?条款?

另外,如何从for compr中删除.get?

for {
  userOption <- userService.getById(1)
  companyOption <- cService.getById(2)
  if (userOption.get.companyId == companyOption.get.id)
} {
      ..
      ..
      saveUser(userOption.get, companyOption.get)
      return ..
}
  1. 所以我在使用for-comp时试图摆脱我的.get调用,怎么样?
  2. 我如何处理我最初的else子句?
  3. 在另一个for-comp中使用for-comp是不好的做法吗?
  4. 在上面的代码中我有一个if(...),然后我调用了blahService.boo()。如果这是returnign的未来,我怎么称呼这个而不让下面的代码在此之前执行?因为它是一个&#39;如果&#39;这让我很困惑。

3 个答案:

答案 0 :(得分:2)

以下是使用Scalaz OptionT的解决方案:

import scalaz.OptionT.optionT

(for {
  user <- optionT(userService.getById(1))
  company <- optionT(cService.getById(2))
  if (user.companyId == company.id)
} yield {
  saveUser(user, company)
}).run

参见例如这个讨论更多:http://loicdescotte.github.io/posts/scala-compose-option-future/

答案 1 :(得分:1)

在将Future与控制流混合时,我强烈推荐scala-async。我发现它几乎严格地优于mapfor - 对Future s的理解。您可以使用哪种控制流结构存在一些限制,但对于您的情况,它会很有效:

async {
  val userOption = await(userService.getById(1))
  val companyOption = await(cService.getById(2))

  (userOption, companyOption) match {
    case (Some(user), Some(company)) => // happy path
    case _ => // sad path
  }
}

整个async {...}块的类型为Future[A],其中Amatch的分支决定。

答案 2 :(得分:0)

如果您被限制为香草Scala,

val x = for {
  userOption    <- userService.getById(1)
  companyOption <- cService.getById(2)

} yield {
  for {
    user    <- userOption
    company <- companyOption
  } yield {
    if (user.id == company.id) { ... }
    else { ... }
  }
}
x

然后就这么简单。

请注意,如果两个调用之一返回Future,则生成的Failure将失败。此外,如果其中一个调用返回Option,则生成的None将为None。这种理解基本上只适用于&#34;快乐的道路&#34;代码,并且可能不足以满足每个不同分支需要采取不同操作的情况。