未使用Await的另一个Future.map中的Future [Future [T]]到Future [T]的未来?

时间:2013-05-29 09:12:28

标签: scala asynchronous jvm scala-2.10

这是一个理论问题。我有一个服务,我可以打电话去做一份工作,但是这项服务可能无法完成所有工作,因此我需要拨打第二个来完成它。

我想知道是否有办法在地图函数中没有Await.result结果的情况下做类似的事情:

val myFirstFuture = asyncRequestA()

myFirstFuture.map(result => {
    result match {
       case isWhatIExpected => result
       case isNot => Await.result(asyncRequestB(), someDuration)
    }
})

我想将asyncRequestB()给出的未来“合并”到myFirstFuture而不使用Await函数来获取结果。

有什么想法吗?

2 个答案:

答案 0 :(得分:6)

Future是一个单子。在Scala中使用monad的标准方法是使用“for comprehension”:

for {
  firstResult <- firstFuture
  secondResult <- firstResult match {
    case isWhatIExpected => Future.successful( firstResult )
    case isNot => asyncRequestB()
  }
}
yield secondResult

在Scala中“for comprehension”是一系列flatMapmapfilter方法应用程序的语法糖,编译器会将这种理解扩展到相同的东西就像瑞吉斯的回答一样。

虽然在这种情况下你可能不会完全看到使用“for comprehension”语法带来的好处,当你放入另一个Future时,当事情开始变得棘手时,它会变得光彩照人。 “理解”基本上做的是它使这三种方法应用程序的嵌套处理变得平坦。

其次,还有一种方法可以通过利用“部分功能”来语法优化Regis的解决方案:

myFirstFuture.flatMap{ 
  case r if isWhatIExpected( r ) => Future.succesful( r )
  case r if isNot( r ) => asyncRequestB()
}

答案 1 :(得分:4)

只需使用flatMap代替map

myFirstFuture.flatMap{ result =>
  result match {
     case isWhatIExpected => Future.successful( result )
     case isNot => asyncRequestB()
  }
}

作为旁注,你甚至可以像这样缩短它:

myFirstFuture.flatMap{
   case result: isWhatIExpected => Future.successful( result )
   case _ => asyncRequestB()
}

另见Nikita Volkov关于使用理解的例子的答案