gpt4 book ai didi

Scala 方式来处理 for-comprehensions 中的条件?

转载 作者:行者123 更新时间:2023-12-04 09:35:22 24 4
gpt4 key购买 nike

我正在尝试创建一个简洁的结构,对基于 future 的业务逻辑进行理解。这是一个示例,其中包含基于异常处理的工作示例:

(for {
// find the user by id, findUser(id) returns Future[Option[User]]
userOpt <- userDao.findUser(userId)
_ = if (!userOpt.isDefined) throw new EntityNotFoundException(classOf[User], userId)

user = userOpt.get

// authenticate it, authenticate(user) returns Future[AuthResult]
authResult <- userDao.authenticate(user)
_ = if (!authResult.ok) throw new AuthFailedException(userId)

// find the good owned by the user, findGood(id) returns Future[Option[Good]]
goodOpt <- goodDao.findGood(goodId)
_ = if (!good.isDefined) throw new EntityNotFoundException(classOf[Good], goodId)

good = goodOpt.get

// check ownership for the user, checkOwnership(user, good) returns Future[Boolean]
ownership <- goodDao.checkOwnership(user, good)
if (!ownership) throw new OwnershipException(user, good)

_ <- goodDao.remove(good)
} yield {
renderJson(Map(
"success" -> true
))
})
.recover {
case ex: EntityNotFoundException =>
/// ... handle error cases ...
renderJson(Map(
"success" -> false,
"error" -> "Your blahblahblah was not found in our database"
))
case ex: AuthFailedException =>
/// ... handle error cases ...
case ex: OwnershipException =>
/// ... handle error cases ...
}

然而,这可能被视为一种非功能性或非 Scala 的处理方式。有一个更好的方法吗?

请注意,这些错误来自不同的来源——有些在业务级别(“检查所有权”),有些在 Controller 级别(“授权”),有些在数据库级别(“找不到实体”)。因此,当您从单个常见错误类型派生它们时,方法可能不起作用。

最佳答案

不要对预期行为使用异常。

它在 Java 中并不好,在 Scala 中也确实不好。请see this question有关为什么应该避免在常规控制流中使用异常的更多信息。 Scala 非常适合避免使用异常:您可以使用 Either s。

诀窍是定义一些您可能遇到的故障,并转换您的 Option s 进入 Either s 包装这些失败。

// Failures.scala
object Failures {
sealed trait Failure

// 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 Eithers for you
implicit class opt2either[A](opt: Option[A]) {
def withFailure(f: Failure) = opt.fold(Left(f))(a => Right(a))
}
}

使用这些助手,您可以使您的理解可读且无异常:
import Failures._    

// Helper function to make ownership checking more readable in the for comprehension
def checkGood(user: User, good: Good) = {
if(checkOwnership(user, good))
Right(good)
else
Left(NoOwnership)
}

// 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)))

// Check result and handle any failures
resultFuture.map { result =>
result match {
case Right(json) => json // serve json
case Left(failure) => failure match {
case UserNotFound => // Handle errors
case NotAuthenticated =>
case GoodNotFound =>
case NoOwnership =>
case _ =>
}
}
}

关于Scala 方式来处理 for-comprehensions 中的条件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24081646/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com