我一直在努力简化我在Scala中做期货的方式。我有一点Future[Option[Future[Option[Boolean]]
,但我在下面进一步简化了它。有没有更好的方法来简化这个?
传递“失败”的未来似乎似乎是最好的方法。即在顺序世界中,我只是返回“FAIL !!”任何时候它失败而不是继续到最后。还有其他方法吗?
val doSimpleWork = Future {
//Do any arbitrary work (can be a different function)
true //or false
}
val doComplexWork = Future {
//Do any arbitrary work (can be a different function)
Some("result") //or false
}
val failed = Future {
//Do no work at all!!! Just return
false
}
val fut1 = doSimpleWork
val fut2 = doSimpleWork
val fut3 = (fut1 zip fut2).map({
case (true, true) => true
case _ => false
})
val fut4 = fut3.flatMap({
case true =>
doComplexWork.flatMap({
case Some("result") =>
doSimpleWork
case None =>
failed
})
case false =>
failed
})
fut4.map({
case true =>
"SUCCESS!!!"
case _ =>
"FAIL!!"
})
答案 0 :(得分:3)
请注意,在您的示例中,因为您急切地将Futures
实例化为val
,所有这些都会在您声明它们(val x = Future {...}
)后立即开始执行。使用方法将使Futures仅在执行链请求时执行。
避免进一步计算的一种方法是抛出异常,然后用onFailure
处理它:
def one = future { println("one") ; Some(1) }
def two = future { println("two") ; throw new Exception("no!"); 2 }
def three = future { println("three") ; 3 }
val f = one flatMap {
result1 => two flatMap {
result2 => three
}
}
f onFailure {
case e: Exception =>
println("failed somewhere in the chain")
}
你可以在这里看到“3”不应该打印出来,因为我们在two
失败了。情况就是这样:
one
two
failed somewhere in the chain
答案 1 :(得分:3)
“Monad变换器”是一个结构,它可以让你结合两个monad的“效果”,scalaz项目提供了几个不同的monad变换器。我的建议是,如果你还使用Option[Unit]
与布尔同构的事实(Some(())
== true
和{{1},你可以使用OptionT monad变换器来简化你的代码。 }} == None
)。这是一个完整的例子:
false
答案 2 :(得分:1)
你可以尝试这样的事情,使用理解来清理代码:
def doSimpleWork = Future{
//do some simple work
true
}
def doComplexWork = Future{
//do something complex here
Some("result")
}
val fut1 = doSimpleWork
val fut2 = doSimpleWork
val fut = for{
f1Result <- fut1
f2Result <- fut2
if (f1Result && f2Result)
f3Result <- doComplexWork
if (f3Result.isDefined)
f4Result <- doSimpleWork
} yield "success"
fut onComplete{
case Success(value) => println("I succeeded")
case Failure(ex) => println("I failed: " + ex.getMessage)
}
如果您真的只想在最后打印出“成功”或“失败”,您可以将最后一段代码更改为:
fut.recover{case ex => "failed"} onSuccess{
case value => println(value)
}
现在,解释发生了什么。对于初学者,我们已经定义了两个返回Futures
的函数来执行异步工作。 doSimpleWork函数将执行一些简单的工作并返回布尔成功/失败指示符。 doComplexWork函数将执行更复杂(和更耗时)的操作并返回表示结果的Option [String]。然后我们在进入for comprehension之前启动两个并行的doSimpleWork调用。在for for comp中,我们在检查它们是否成功之前得到fut1
和fut2
的结果(按此顺序)。如果没有,我们将停在这里,fut
val将失败,NoSuchElementException
这就是当这样的条件在for comp中失败时你得到的。如果两者都成功,我们将继续并调用doComplexWork函数并等待其结果。然后我们检查它的结果,如果它是Some
,我们将开始最后一次调用doSimpleWork。如果成功,我们将产生字符串“success”。如果您检查fut
val的类型,其类型为Future[String]
。
从那里,我们使用一个异步回调函数来检查整个调用序列是否一直通过(Success
情况),或者在进程中的某个地方失败({{1 (例)),打印出与其遇到的案例相关的内容。在备用最终代码块中,我们通过返回String“failed”来恢复任何可能的失败,然后仅使用Failure
回调,根据发生的情况打印“成功”或“失败”。