概述
从 Swift 语言诞生那天儿起,它就不厌其烦一遍又一遍地向秃头码农们诉说着自己的类型安全和高雅品味。
不过遗憾的是,作为 Swift 语言中错误处理这最为重要的一环却时常让小伙伴们不得要领、满腹狐疑。
在本篇博文中,您将学到如下内容:
- 概述
- 1. Swift 6.0 之前的错误机制
- 2. Swift 6.0 全新的特定错误抛出机制
- 3. 旧机制的向后兼容性
- 总结
从 Swift 6.0 开始,苹果为 Swift 添加了全新的错误类型限定机制,我们从此对各种方法究竟抛出何种错误将会始终了然于胸、一目了然。
闲言少叙,让我们马上开始错误抛出大冒险吧!
Let‘s go!!!😉
1. Swift 6.0 之前的错误机制
众所周知,为任何语言提供错误处理之道都是至关重要的“硬核”操作,Swift 自然也不例外。
在 Swift 6.0 之前,我们可以这样考虑特定方法发生错误时的处理方式:
enum FooError: Error {
case tooBig
case tooSmall
}
func foo() throws -> Int {
let value = Int.random(in: 1...100)
guard value < 60 else {
throw FooError.tooBig
}
guard value > 20 else {
throw FooError.tooSmall
}
return value
}
从上面的代码可以看到,我们定义了一个 FooError 错误类型,然后在 foo 方法中根据实际情况抛出其中的错误。
我们可以这样调用 foo 方法:
func boo() {
do {
let value = try foo()
print(value)
} catch let error as FooError {
switch error {
case .tooBig: print("Too big...")
case .tooSmall: print("Too small...")
}
} catch {
print("General erro: \(error)")
}
}
如您所见:我们使用 do…catch 语法块捕获了 foo 方法调用时可能发生的错误。注意,为了准确我们需要显式“解包”捕获的错误类型。这样会带来几个问题:
- 如果不看 foo 方法的源代码,无法确切知道它到底会抛出什么样的错误;
- catch 必须指定具体的错误类型;(当然不指定也可以,但这种情况不在本篇考虑之内)
- 无法在编译期间发现不适当的错误捕获代码;
为了不让头发已经所剩无几的秃头码农们再揪心于任意方法可能犯下的“弥天大错”,Swift 必须做些什么!
That’s Right!!!
2. Swift 6.0 全新的特定错误抛出机制
好消息来了:从 Swift 6.0 开始我们可以“名正言顺”的让方法抛出指定类型的错误啦!这是通过在方法签名中指明错误类型来实现的:
enum FooError: Error {
case tooBig
case tooSmall
}
func foo() throws(FooError) -> Int {
let value = Int.random(in: 1...100)
guard value < 60 else {
throw FooError.tooBig
}
guard value > 20 else {
throw FooError.tooSmall
}
return value
}
在上面的代码中,我们紧接着在 foo 方法定义的 throws 关键字后面添加了可能抛出的错误类型。这样做的好处是:同时让编译器和调用者单凭方法签名就能明了该方法可能抛出的错误了。
而且这样一来,由于编译器对可能抛出的错误已然一清二楚,所以我们捕获 foo 方法错误的代码还可以进一步简化:
func boo() {
do {
let value = try foo()
print(value)
} catch {
switch error {
case .tooBig: print("Too big...")
case .tooSmall: print("Too small...")
}
}
}
看到了吗?有了方法抛出错误类型的显式申明之后,我们在 catch 子句中无需再喋喋不休的“解包 Unwrap”实际的错误类型了!是不是很赞呢?
3. 旧机制的向后兼容性
在 Swift 6.0 中,之前的错误抛出和处理机制仍然被延续下来,从而做到连贯而统一。
比如下面的代码:
func foo() throws {}
在 Swift 6.0 中会在“背后”悄悄变为如下形式:
func foo() throws(any Error) {}
这意味着,如果我们在 Swift 6.0 中为不可抛出错误(throws)的方法限定错误类型,Swift 就视其为 any Error。
甚至原本绝不会抛出错误的方法:
func foo() {}
在 Swift 6.0 中也会“偷偷”抛出一个“所谓的” Never 错误类型:
func foo() throws(Never) {}
看到这里,小伙伴们是否对 Swift 6.0 中全新的错误抛出和处理机制一清二楚了呢?棒棒哒!💯
想要系统学习 Swift 的各位小伙伴们,赶快到我的《Swift语言开发精讲》专栏来逛一逛吧:
- Swift 语言开发精讲 - 大熊猫侯佩
总结
在本篇博文中,我们讨论了在 Swift 6.0 中如何更加优雅的抛出和处理指定类型的错误,并顺便聊了聊 Swift 6.0 之前的旧机制如何一致的做到向后兼容。
感谢观赏,再会啦!😎