这是一个理论问题。我有一个服务,我可以打电话去做一份工作,但是这项服务可能无法完成所有工作,因此我需要拨打第二个来完成它。
我想知道是否有办法在地图函数中没有Await.result
结果的情况下做类似的事情:
val myFirstFuture = asyncRequestA()
myFirstFuture.map(result => {
result match {
case isWhatIExpected => result
case isNot => Await.result(asyncRequestB(), someDuration)
}
})
我想将asyncRequestB()
给出的未来“合并”到myFirstFuture
而不使用Await函数来获取结果。
有什么想法吗?
答案 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”是一系列flatMap
,map
和filter
方法应用程序的语法糖,编译器会将这种理解扩展到相同的东西就像瑞吉斯的回答一样。
虽然在这种情况下你可能不会完全看到使用“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关于使用理解的例子的答案