为什么“抛出"在 Swift 中不是类型安全的? [英] Why is 'throws' not type safe in Swift?

查看:23
本文介绍了为什么“抛出"在 Swift 中不是类型安全的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Swift 中最大的误解是 throws 关键字.考虑以下代码:

The biggest misunderstanding for me in Swift is the throws keyword. Consider the following piece of code:

func myUsefulFunction() throws

我们无法真正理解它会抛出什么样的错误.我们唯一知道的是它可能会抛出一些错误.了解错误可能是什么的唯一方法是查看文档或在运行时检查错误.

We cannot really understand what kind of error it will throw. The only thing we know is that it might throw some error. The only way to understand what the error might be is by looking at the documentation or checking the error at runtime.

但这不是违背 Swift 的本性吗?Swift 拥有强大的泛型和类型系统来使代码具有表现力,但感觉好像 throws 正好相反,因为您无法通过查看函数签名获得任何关于错误的信息.

But isn't this against Swift's nature? Swift has powerful generics and a type system to make the code expressive, yet it feels as if throws is exactly opposite because you cannot get anything about the error from looking at the function signature.

为什么会这样?还是我错过了一些重要的东西并误解了这个概念?

Why is that so? Or have I missed something important and mistook the concept?

推荐答案

选择是经过深思熟虑的设计决定.

The choice is a deliberate design decision.

他们不希望出现不需要像在 Objective-C、C++ 和 C# 中那样声明异常抛出的情况,因为这使得调用者必须要么假设所有函数都抛出异常并包含样板来处理可能不会发生的异常,或者只是忽略异常的可能性.这两个都不理想,第二个使得异常不可用,除非你想终止程序,因为你不能保证调用堆栈中的每个函数在堆栈展开时都正确释放了资源.

They did not want the situation where you don't need to declare exception throwing as in Objective-C, C++ and C# because that makes callers have to either assume all functions throw exceptions and include boilerplate to handle exceptions that might not happen, or to just ignore the possibility of exceptions. Neither of these are ideal and the second makes exceptions unusable except for the case when you want to terminate the program because you can't guarantee that every function in the call stack has correctly deallocated resources when the stack is unwound.

另一个极端是你所提倡的想法,即可以声明抛出的每种类型的异常.不幸的是,人们似乎反对这样做的后果,即您有大量的 catch 块,因此您可以处理每种类型的异常.因此,例如,在 Java 中,它们将抛出 Exception 将情况减少到与我们在 Swift 中相同或更糟的情况,它们使用未经检查的异常,因此您可以完全忽略问题.GSON 库是后一种方法的一个例子.

The other extreme is the idea you have advocated and that each type of exception thrown can be declared. Unfortunately, people seem to object to the consequence of this which is that you have large numbers of catch blocks so you can handle each type of exception. So, for instance, in Java, they will throw Exception reducing the situation to the same as we have in Swift or worse, they use unchecked exceptions so you can ignore the problem altogether. The GSON library is an example of the latter approach.

我们选择使用未经检查的异常来指示解析失败.这样做主要是因为客户端通常无法从错误的输入中恢复,因此强制它们捕获已检查的异常会导致 catch() 块中的代码马虎.

We chose to use unchecked exceptions to indicate a parsing failure. This is primarily done because usually the client can not recover from bad input, and hence forcing them to catch a checked exception results in sloppy code in the catch() block.

https://github.com/google/gson/blob/master/GsonDesignDocument.md

这是一个非常糟糕的决定.您不能信任自己进行错误处理,因此您的应用程序应该崩溃".

That is an egregiously bad decision. "Hi, you can't be trusted to do your own error handling, so your application should crash instead".

就我个人而言,我认为 Swift 取得了正确的平衡.您必须处理错误,但您不必编写大量 catch 语句来执行此操作.如果再进一步,人们就会想办法颠覆这个机制.

Personally, I think Swift gets the balance about right. You have to handle errors, but you don't have to write reams of catch statements to do it. If they went any further, people would find ways to subvert the mechanism.

设计决定的完整理由在 https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst

The full rationale for the design decision is at https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst

编辑

似乎有些人对我所说的某些事情有疑问.所以这里有一个解释.

There seems to be some people having problems with some of the things I have said. So here is an explanation.

程序可能抛出异常的原因有两大类.

There are two broad categories of reasons why a program might throw an exception.

  • 程序外部环境中的意外情况,例如文件上的 IO 错误或格式错误的数据.这些是应用程序通常可以处理的错误,例如通过向用户报告错误并允许他们选择不同的操作方案.
  • 编程中的错误,例如空指针或数组绑定错误.解决这些问题的正确方法是让程序员更改代码.

第二种类型的错误通常不应被捕获,因为它们表明对环境的错误假设可能意味着程序数据已损坏.我没有办法安全地继续,所以你必须中止.

The second type of error should not, in general be caught, because they indicate a false assumption about the environment that could mean the program's data is corrupt. There my be no way to continue safely, so you have to abort.

第一种错误通常是可以恢复的,但是为了安全恢复,每个栈帧都必须正确展开,这意味着每个栈帧对应的函数必须意识到它调用的函数可能会抛出异常并采取措施确保在抛出异常时所有内容都得到一致清理,例如使用 finally 块或等效项.如果编译器不支持告诉程序员他们忘记计划异常,程序员就不会总是计划异常,并且会编写泄漏资源或使数据处于不一致状态的代码.

The first type of error usually can be recovered, but in order to recover safely, every stack frame has to be unwound correctly which means that the function corresponding to each stack frame must be aware that the functions it calls may throw an exception and take steps to ensure that everything gets cleaned up consistently if an exception is thrown, with, for example, a finally block or equivalent. If the compiler doesn't provide support for telling the programmer they have forgotten to plan for exceptions, the programmer won't always plan for exceptions and will write code that leaks resources or leaves data in an inconsistent state.

gson 态度如此骇人听闻的原因是因为他们说你无法从解析错误中恢复(实际上,更糟糕的是,他们告诉你,你缺乏从解析错误中恢复的技能).断言这是一件荒谬的事情,人们一直试图解析无效的 JSON 文件.如果有人错误地选择了一个 XML 文件,我的程序崩溃是一件好事吗?不,不是.它应该报告问题并要求他们选择不同的文件.

The reason why the gson attitude is so appalling is because they are saying you can't recover from a parse error (actually, worse, they are telling you that you lack the skills to recover from a parse error). That is a ridiculous thing to assert, people attempt to parse invalid JSON files all the time. Is it a good thing that my program crashes if somebody selects an XML file by mistake? No isn't. It should report the problem and ask them to select a different file.

顺便说一下,gson 只是一个例子,说明为什么对可以从中恢复的错误使用未经检查的异常是不好的.如果我确实想从某人选择 XML 文件中恢复,我需要捕获 Java 运行时异常,但是哪些异常呢?好吧,我可以查看 Gson 文档以找出答案,假设它们是正确的并且是最新的.如果它们带有已检查的异常,API 会告诉我会出现哪些异常,如果我不处理它们,编译器会告诉我.

And the gson thing was, by the way, just an example of why using unchecked exceptions for errors you can recover from is bad. If I do want to recover from somebody selecting an XML file, I need to catch Java runtime exceptions, but which ones? Well I could look in the Gson docs to find out, assuming they are correct and up to date. If they had gone with checked exceptions, the API would tell me which exceptions to expect and the compiler would tell me if I don't handle them.

这篇关于为什么“抛出"在 Swift 中不是类型安全的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆