[英]Future[A] vs Future[Throwable \/ A]
Why do some people bother to represent failure in a scala.concurrent.Future
using scala's Either
or scalaz's \\/
instead of using the failed state of the Future? 为什么有些人不愿意使用scala的
Either
或scalaz的\\/
来代表scala.concurrent.Future
失败,而不是使用Future的失败状态?
How do you handle errors then and how do you chain calls on the happy path? 那你如何处理错误呢?你如何在快乐的道路上连接电话?
Update with some examples: 更新一些例子:
converting Akka's Future[A] to Future[Either[Exception,A]] 将Akka的未来[A]转换为未来[要么[例外,A]]
Scalaz Task - the missing documentation This one answers the why part, and suggests using scalaz.EitherT
for chaining calls (that's for \\/
, what about Either
or Try
?), but I wonder if one should ever use Future.failed
, on what conditions, etc, and how to check failure. Scalaz任务 - 缺少的文档这个回答了为什么部分,并建议使用
scalaz.EitherT
来链接调用(这是为了\\/
,或者是Either
还是Try
?),但是我想知道是否应该使用Future.failed
,on what what条件等,以及如何检查失败。
I'm not sure if this is a widespread practice though, that's why I'm asking. 我不确定这是否是一种普遍的做法,这就是为什么我要问。 :)
:)
I personally use Either inside a future when I have "failures that I can expect" and can do something to recover from them. 当我遇到“我能期待的失败”时,我个人会在未来使用Either,并且可以做些什么来从中恢复。 Especially if I need to make information about possible failures explicit to external users of API
特别是如果我需要向API的外部用户显示可能的故障信息
sealed trait UserServiceError
case object UserDbNotAvailable extends UserServiceError
case object UserNotFoung extends UserServiceError
def getUser(id: Long): Future[UserServiceError \/ User]
This code is much more explicit about what failures can happen. 此代码更明确地说明了可能发生的故障。 In some cases it can be important.
在某些情况下,它可能很重要。
The same can be achieved with Future[User] and Future.recover but in this case information about possible failures is not in type (can be in documentation) 使用Future [User]和Future.recover可以实现相同的功能,但在这种情况下,有关可能的故障的信息不在类型中(可以在文档中)
However I agree that it's very controversial design decision, because Try is already designed for failure handling. 但是我同意这是一个非常有争议的设计决定,因为Try已经设计用于故障处理。
I treat the failed state of Future
the same way I treat exceptions: they're for unexpected failures that indicate either programming errors or system failures like OutOfMemoryError
s. 我对待
Future
的失败状态的方式与对待异常的方式相同:它们用于表示程序错误或系统故障(例如OutOfMemoryError
的意外故障。 As such they're not expected to be caught or handled except in a very high-level "retry the whole task" way. 因此,除非以非常高级的“重试整个任务”方式,否则不要捕获或处理它们。
Failed futures are not very typesafe (a failure is just Throwable
), and can conflate these system-level failures with a more semantic failure that can be handled in a predictable way. 失败的Future并不是非常安全的类型(失败只是
Throwable
),并且可以将这些系统级失败与更语义的失败(可以通过可预测的方式处理)混为一谈。 So if I have a failure "within" my system, eg Unauthorized
, then I'd rather represent that as an Either
, something like Future[Unauthorized \\/ MessageData]
. 因此,如果我的系统“内部”发生故障,例如
Unauthorized
,那么我宁愿将其表示为Either
,例如Future[Unauthorized \\/ MessageData]
。 Then there are three possible states: 然后有三种可能的状态:
Success(\\/-(data))
- success Success(\\/-(data))
- 成功 Success(-\\/(unauthorized))
- "expected" failure. Success(-\\/(unauthorized))
- “预期”失败。 Something that I know how to handle specificly, eg by displaying a particular message to the user or returning a particular return code. Failure(throwable)
- unexpected, system-level failure. Failure(throwable)
-系统级意外故障。 Can only be handled with a generic error page or some such. I used to use a monad transformer to make composing the happy path easier (ie EitherT[Future, Unauthorized, MessageData]
), which works very well, though now I'm looking at a more generic approach (my scalaz-transfigure library). 我曾经使用monad转换器使编写幸福的路径变得更容易(
EitherT[Future, Unauthorized, MessageData]
),效果很好,尽管现在我正在寻找一种更通用的方法(我的scalaz-transfigure库)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.