Scala - Futures 和 Eithers
Scala - Futures and Eithers
这个帖子让我了解了如何构建我的代码: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证实了这一点,新的问题是:我应该如何编写这段代码,所以它看起来并不难看,但是整洁有序?
我相信您收到的答案不必要地将 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)
}
}
}
现在您可以将 Future[Option[A]]
映射到 Future[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!)。
这个帖子让我了解了如何构建我的代码: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证实了这一点,新的问题是:我应该如何编写这段代码,所以它看起来并不难看,但是整洁有序?
我相信您收到的答案不必要地将 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)
}
}
}
现在您可以将 Future[Option[A]]
映射到 Future[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!)。