我读过很多关于Scala Futures减少回调问题的文章。我有一个看起来开始有问题的代码。

val a = Future(Option(Future(Option(10))))

a.map { b =>
  b.map { c =>
    c.map { d =>
      d.map { res =>
        res + 10
      }
    }
  }
}

如何使此代码更平坦?

//编辑@againstmethod
for{
  b <- a
  c <- b
  d <- c
  res <- d
} yield res + 10

此代码无法编译

最佳答案

您可以使用for comprehension。例如:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

object Stuff extends App {
  val result = for {
    f1 <- Future { 10 + 1 }
    f2 <- Future { f1 + 2 }
  } yield f2
  result.onComplete(println)
}

结果将是13。

任何实现了正确的mapflatMap函数的类都可以在for中以这种方式使用。

如果您不介意其他依赖项,则还可以使用scalaz之类的库,并显式使用monadic绑定(bind)使内容变平(EDIT编码了一些Option类型,以在下面解决注释):
import scalaz._
import Scalaz._
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.util.{Success,Failure}

object BindEx extends App {

  def f1(i: String): Future[Int] = Future { i.length }
  def f2(i: Int): Future[Option[Double]] = Future { Some(i / Math.PI) }
  def f3(i: Option[Double]): Future[Option[Double]] = Future {
    i match {
      case Some(v) => Some(Math.round(v))
      case _ => None
    }
  }

  val result =
    Monad[Future].point("Starting Point") >>=
    f1 >>=
    f2 >>=
    f3

  result.onComplete { x =>
    x match {
      case Success(value) => println("Success " + value)
      case Failure(ex) => println(ex)
    }
  }

  Await.result(result, 1 seconds)
}

最后,如果在成功之后,如果您仅具有要绑定(bind)的并行操作,则可以使用scalaz应用程序生成器:
  val result = (
    Future { 10 + 10 } |@|
    Future { 20 - 3 } |@|
    Future { Math.PI * 15 }
  ) { _ + _ / _}
  println(Await.result(result, 1 seconds))

这将使所有3个 future 完成,然后将block应用于3个参数。

关于Scala future 回调 hell ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28343904/

10-16 14:00