0

这个线程让我知道如何构建我的代码: Scala-way to handle conditions in for-comprehensions?

有问题的部分:

// First create the JSON
val resultFuture: Future[Either[Failure, JsResult]] = for {
  userRes <- userDao.findUser(userId)
  user    <- userRes.withFailure(UserNotFound).right
  authRes <- userDao.authenticate(user)
  auth    <- authRes.withFailure(NotAuthenticated).right
  goodRes <- goodDao.findGood(goodId)
  good    <- goodRes.withFailure(GoodNotFound).right
  checkedGood <- checkGood(user, good).right
} yield renderJson(Map("success" -> true)))

这是我不明白的行:

user    <- userRes.withFailure(UserNotFound).right
authRes <- userDao.authenticate(user)

userRes.withFailure (UserNotFound).right映射到userDao.authenticate(user)。这将创建一个新的 Either,其右侧有一个 Future,对吗?

怎么能

val resultFuture: Future[Either[Failure, JsResult]]

属于它的类型。我认为应该有另一个未来,而不是 JsResult。谁能给我解释一下?

编辑:由于 cmbaxter 和 Arne Claassen 证实了这一点,新的问题是:我应该如何编写这段代码,这样它看起来并不难看,而是干净和结构化?

4

1 回答 1

4

Either我相信当Future' 已经完全有能力传达失败时,你收到的答案不必要地混入了混合中。您缺少的主要内容是一种Option在不显式抛出异常的情况下从选项值获取的方法。

我建议您将 Failures 对象更改为以下内容:

object Failures {

  sealed trait Failure extends Exception

  // Four types of possible failures here
  case object UserNotFound extends Failure

  case object NotAuthenticated extends Failure

  case object GoodNotFound extends Failure

  case object NoOwnership extends Failure

  // Put other errors here...

  // Converts options into Futures
  implicit class opt2future[A](opt: Option[A]) {
    def withFailure(f: Failure) = opt match {
      case None => Future.failed(f)
      case Some(x) => Future.successful(x)
    }
  }
}

现在您可以将 a 映射Future[Option[A]]到 aFuture[A]并指定失败条件,从而得到如下的 for 理解:

def checkGood(user: User, good: Good) =
  if (checkOwnership(user, good))
    Future.successful(good)
  else
    Future.failed(NoOwnership)

val resultFuture: Future[JsResult] = for {
  userOpt <- userDao.findUser(userId)
  user <- userOpt.withFailure(UserNotFound)
  authOpt <- userDao.authenticate(user)
  auth <- authOpt.withFailure(NotAuthenticated)
  goodOpt <- goodRes.withFailure(GoodNotFound)
  checkedGood <- checkGood(user, good)
} yield renderJson(Map("success" -> true))))

现在您有了一个,Future[JsResult]您可以将失败的场景映射到您想要的输出,而成功的场景就是 JsResult。希望您在一个异步框架中使用它,该框架期望您为它提供一个未来,并且有它自己的失败未来到错误响应映射(例如 Play!)。

于 2015-04-29T17:40:29.497 回答