Scala:最有条理的方式来有条件地执行一个Future取决于另一个?

时间:2014-05-27 07:11:57

标签: scala future

执行以下操作的最惯用和最简洁的方法是:根据以前的执行情况执行或未执行的未来,如下所示:

def getItFromHere : Future[Option[Something]] = ...

def getItFromThere : Future[Option[Something]] = ...

def getIt : Future[Option[Something]] = {

    for {
        maybeSomething <- getItFromHere
        probablySomething <- maybeSomething.getOrElse(getItFromThere) // Obviously can't be done!!!
    }
    yield probablySomething
}

特定用例示例: 从缓存中获取一个项目,只有在缓存中找不到它,才能从数据库中获取它。

我在这里假设getItFromHeregetItFromThere不会因异常而失败。他们将返回Some [Something]或None。请随意考虑这一假设,或者在没有它的情况下给予更好的假设。

注意:我理解for-comprehension的内部机制,它实际上是内部转换为map / flatMap / filter。

3 个答案:

答案 0 :(得分:6)

如果在缓存中找不到任何项目,然后通过检索恢复它,您可能会失败。

// assuming getItFromHere() fails if no item is found
getItFromHere() recoverWith { case _ => getItFromThere() }

或者使用Option你可以这样做:

getItFromHere() flatMap {
  case Some(x) => Future.successful(Some(x))
  case None => getItFromThere()
}

答案 1 :(得分:2)

其实你的例子几乎就在那里。您只需要匹配monadic组合所期望的Future类型:

for {
     fut <- someFuture
     something <- fut.map(x=>someFuture).getOrElse(someBetterFuture)
} yield something

为简单起见,此处someFutureval。如果您使用def,请避免重新计算操作,方法是将结果打包回以后。折叠到问题代码中:

for {
     maybeSomething <- getItFromHere
     probablySomething <- maybeSomething.map(x=> Future.succcessful(maybeSomething)).getOrElse(getItFromThere)
} yield probablySomething

答案 2 :(得分:2)

如果你使用scalaz的OptionT变换器:

def getItFromHere : OptionT[Future,Something] = OptionT(...)

def getItFromThere : OptionT[Future,Something] = OptionT(...)

def getIt : Future[Option[Something]] = (getItFromHere orElse getItFromThere).run