未来[期权[期货[期权[布尔]]简化期货和期权?

时间:2013-04-30 03:01:29

标签: scala akka

我一直在努力简化我在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!!"
})

3 个答案:

答案 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中,我们在检查它们是否成功之前得到fut1fut2的结果(按此顺序)。如果没有,我们将停在这里,fut val将失败,NoSuchElementException这就是当这样的条件在for comp中失败时你得到的。如果两者都成功,我们将继续并调用doComplexWork函数并等待其结果。然后我们检查它的结果,如果它是Some,我们将开始最后一次调用doSimpleWork。如果成功,我们将产生字符串“success”。如果您检查fut val的类型,其类型为Future[String]

从那里,我们使用一个异步回调函数来检查整个调用序列是否一直通过(Success情况),或者在进程中的某个地方失败({{1 (例)),打印出与其遇到的案例相关的内容。在备用最终代码块中,我们通过返回String“failed”来恢复任何可能的失败,然后仅使用Failure回调,根据发生的情况打印“成功”或“失败”。