Swift 为什么没有异常处理?

个人感觉异常处理非常重要(难道不重要?)
关注者
229
被浏览
19234
「异常处理」和「使用 try/catch 来处理异常」是马与白马的关系。Swift 有异常处理,或者说使用 Swift 当然可以处理异常,只不过不是用 try/catch 这样的机制或语法。C 没有 try/catch,Perl 没有,Lua 没有,Go 也没有,但是这些语言都有别的机制处理异常,大家照样用得好好的。

即便是提供了 try/catch 机制的语言,对待它的态度也不大一样。Java / C# 里面 try/catch block 属于要节制使用的工具,用 try/catch 来决定 control flow 更是欺师灭祖的罪名;可在 Python 里面 try/except 常年兼职做 if-else,Pythonista 们眉头都不皱一下——这跟语言的设计理念和抛异常的性能有关。但 try/catch 机制的主要问题可能是容易被滥用,初学者把有问题的代码块包起来 try 一脚再 catch 住万恶的异常基类,哇噻程序顿时不崩溃了腰不疼了腿不酸了鲁棒了 bug free 了。可即便意识到这样做是鸵鸟式的 anti-pattern,又会发现 try/catch 属于「很容易上手但很难成为高手」的特性,仍旧会在「根本不确定能踹到什么,所以也总要推敲到底能抓到什么」的阶段徘徊。许多高手因此相当排斥 try/catch [1][2][3]。

以苹果开发的角度来说,异常处理可以细分成对于「错误(error)」和「异常(exception)」两类情况的处理,前者是可以预见到发生可能性的、可以恢复的非致命错误,比如找不到指定位置的文件或者网络忽然断开之类,在 Objective-C 中由 NSError 代表,Java 中的对应物是 checked exception,基类是 lang.Exception;后者则是无法预见通常也不可恢复的致命错误,比如磁盘坏了、内存没了之类,在 Objective-C 中由 NSException 代表,Java 中则是 RuntimeException 这样的所谓 unchecked exception[4]。Objective-C 中对于前者的处理是判断可能产生错误的方法的返回值,并传入一个 NSError ** 类型的指针指针去获取生成的 NSError 对象来看看错误究竟是什么,对于后者才使用 @try/@catch;而 Java / C# 中则是两者均使用 try/catch 处理。

但问题是 Objective-C 虽然有 @try/@catch,苹果的范例代码中却很少使用到它(至少是在 iOS 部分),苹果对 try/catch 的态度也是限制用在「programming or unexpected runtime errors」[5],像在 Java 里那样用 try/catch 在 Obj-C 中完全行不通。而且 Obj-C 可能出现的异常也不是全都能由 NSException 代表,有些异常必须在 C 级别 trap。总之,try/catch 不是苹果鼓励的开发范式,Cocoa 程序员也极少用它,甚至你会觉得苹果开发者们对 exception 的态度就是「反正也不知道该怎么处理索性就让程序 crash 好了」(我觉得这个态度挺好的,fail fast 是件好事[6]),所以专为 Cocoa 开发而推出的 Swift 没有 try/catch 也并不是很意外的事情。当然,我也不敢斩钉截铁地说未来版本里 try/catch 肯定不会出现(二〇一五年六月八日更新:Swift 2 已经有了 do{} catch{} ),因为 Swift 毕竟和 Obj-C 共享运行时,如果 Swift 有朝一日也会要拿来写一些不得不处理底层抛上来的 NSException 的东西,那就必须能提供某种错误恢复机制,而不是简单地 crash。

(Swift 处理 NSError 的范式与 Objective-C 基本一致,而且有 optional 的助益,变得更简洁了。)

又,开发者论坛上关于这个话题已经有很长的讨论: devforums.apple.com/thr (需登录)

[1] Cleaner, more elegant, and wrong 以及 Cleaner, more elegant, and harder to recognize
[2] joelonsoftware.com/item
[3] groups.google.com/forum
[4] Java 中 RuntimeException 继承自 Exception,Obj-C 中 NSError 和 NSException 各自继承自 NSObject。另外 Java 还有一个 lang.Error,并不继承自 Exception,也可以视为一种 unchecked exception。
[5] Exception Programming Topics: Introduction to Exception Programming Topics for Cocoa
[6] martinfowler.com/ieeeSo