简体   繁体   English

为什么`scala.util.Try`在“Scala中的函数式编程”一书中的“无异常处理错误”一章中没有提到?

[英]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中的函数式编程”一书的“无异常处理错误”一章中,作者给出了:

  1. The problem of throwing exceptions from the body of a function 从函数体中抛出异常的问题
  2. Use Option if we don't care about the actual exception 如果我们不关心实际的异常,请使用Option
  3. Use 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 mapflatMap明确设计用于处理可能抛出异常的函数。 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版本,其中mapflatMap方法没有捕获异常,并且仍然有充分的理由在可能的情况下避免使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM