[英]Why `scala.util.Try` is not mentioned in chapter “Handling errors without exceptions” of book “functional programming in Scala”?
In the chapter "Handling errors without exceptions" of book "functional programming in Scala", the author gives: 在“Scala中的函数式编程”一书的“无异常处理错误”一章中,作者给出了:
Option
if we don't care about the actual exception Option
Either
if we care about the actual exception Either
如果我们关心实际的异常 But scala.util.Try
is not mentioned. 但是没有提到
scala.util.Try
。 From my point of view, I think Try
is very suitable when we care about the actual exception, why it's not mentioned? 从我的角度来看,我认为
Try
非常适合我们关心的实际异常,为什么没有提到? Is there any reason I have missed? 我错过了什么理由?
I'm neither of the authors of Functional Programming in Scala, but I can make a few guesses about why they don't mention Try
. 我既不是Scala中的函数编程的作者,但我可以猜测为什么他们不提
Try
。
Some people don't like the standard library's Try
because they claim it violates the functor composition law . 有些人不喜欢标准库的
Try
因为他们声称它违反了functor组合法 。 I personally think that this position is kind of silly, for the reasons Josh Suereth mentions in the comments of SI-6284, but the debate does highlight an important aspect of Try
's design. 我个人认为这个位置有点愚蠢,因为Josh Suereth在SI-6284的评论中提到的原因,但辩论确实强调了
Try
的设计的一个重要方面。
Try
's map
and flatMap
are explicitly designed to work with functions that may throw exceptions. Try
map
和flatMap
明确设计用于处理可能抛出异常的函数。 People from the FPiS school of thought (including me) would tend to suggest wrapping such functions (if you absolutely have to deal with them at all) in safe versions at a low level in your program, and then exposing an API that will never throw (non-fatal) exceptions. 来自FPiS思想学派(包括我)的人倾向于建议在程序中的低级安全版本中包装这些函数(如果你绝对必须处理它们),然后公开一个永不抛出的API (非致命)例外。
Including Try
in your API muddles up the layers in this model—you're guaranteeing that your API methods won't throw exceptions, but then you're handing people a type that's designed to be used with functions that throw exceptions. 包括
Try
在你的API中混淆了这个模型中的层 - 你保证你的API方法不会抛出异常,但是你会给人们一个设计用于抛出异常的函数的类型。
That's only a complaint about the standard library's design and implementation of Try
, though. 不过,这只是对标准库的
Try
设计和实现的抱怨。 It's easy enough to imagine a version of Try
with different semantics, where the map
and flatMap
methods didn't catch exceptions, and there would still be good reasons to avoid this "improved" version of Try
whenever possible. 很容易想象一个具有不同语义的
Try
版本,其中map
和flatMap
方法没有捕获异常,并且仍然有充分的理由在可能的情况下避免使用Try
“改进”版本。
One of these reasons is that using Either[MyExceptionType, A]
instead of Try[A]
makes it possible to get more mileage out of the compiler's exhaustivity checking. 其中一个原因是使用
Either[MyExceptionType, A]
而不是Try[A]
可以从编译器的穷举检查中获得更多的里程数。 Suppose I'm using the following simple ADT for errors in my application: 假设我在我的应用程序中使用以下简单的ADT来解决错误:
sealed class FooAppError(message: String) extends Exception(message)
case class InvalidInput(message: String) extends FooAppError(message)
case class MissingField(fieldName: String) extends FooAppError(
s"$fieldName field is missing"
)
Now I'm trying to decide whether a method that can only fail in one of these two ways should return Either[FooAppError, A]
or Try[A]
. 现在我试图确定一个只能以这两种方式之一失败的方法是否应该返回
Either[FooAppError, A]
或Try[A]
。 Choosing Try[A]
means we're throwing away information that's potentially useful both to human users and to the compiler. 选择
Try[A]
意味着我们丢弃了对人类用户和编译器都有用的信息。 Suppose I write a method like this: 假设我写了一个这样的方法:
def doSomething(result: Either[FooAppError, String]) = result match {
case Right(x) => x
case Left(MissingField(_)) => "bad"
}
I'll get a nice compile-time warning telling me that the match is not exhaustive. 我会得到一个很好的编译时警告,告诉我这场比赛并非详尽无遗。 If I add a case for the missing error, the warning goes away.
如果我为丢失的错误添加一个案例,警告就会消失。
If I had used Try[String]
instead, I'd also get exhaustivity checking, but the only way to get rid of the warning would be to have a catch-all case—it's just not possible to enumerate all Throwable
s in the pattern match. 如果我使用了
Try[String]
,我也会进行穷举检查,但摆脱警告的唯一方法就是拥有一个包罗万象的案例 - 它不可能枚举模式中的所有Throwable
比赛。
Sometimes we actually can't conveniently limit the kinds of ways an operation can fail to our own failure type (like FooAppError
above), and in these cases we can always use Either[Throwable, A]
. 有时我们实际上不能方便地限制操作失败的方式类型(如上面的
FooAppError
),在这些情况下我们总是可以使用Either[Throwable, A]
。 Scalaz's Task
, for example, is essentially a wrapper for Future[Throwable \\/ A]
. 例如,Scalaz的
Task
本质上是Future[Throwable \\/ A]
的包装器。 The difference is that Either
(or \\/
) supports this kind of signature, while Try
requires it. 不同之处在于,
Either
(或\\/
) 支持这种签名,而Try
需要它。 And it's not always what you want, for reasons like useful exhaustivity checking. 由于有用的穷举检查等原因,并不总是你想要的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.