1. throws 关键字
- 作用:标记函数/方法可能抛出错误,强制调用者处理错误(使用
try、try?或try!)。 - 适用场景:函数内部存在可能抛出错误的操作。
- 代码示例:
// 定义错误类型
enum NetworkError: Error {
case invalidURL
case requestFailed
}
// 使用 throws 的函数
func fetchData(from urlString: String) throws -> Data {
guard let url = URL(string: urlString) else {
throw NetworkError.invalidURL // 主动抛出错误
}
// 模拟网络请求(实际可能用 URLSession)
if urlString.isEmpty {
throw NetworkError.requestFailed
}
return Data() // 成功返回数据
}
// 调用 throws 函数必须处理错误
do {
let data = try fetchData(from: "https://example.com")
print("数据获取成功: \(data)")
} catch {
print("错误: \(error)") // 捕获并处理错误
}
2. rethrows 关键字
- 作用:标记函数本身不主动抛出错误,但会将传入的闭包参数的错误向上传递。
- 适用场景:高阶函数(接受闭包作为参数),且错误来源仅限于闭包。
- 代码示例:
// 定义一个 rethrows 的高阶函数
func processNumbers(_ numbers: [Int], using closure: (Int) throws -> Int) rethrows -> [Int] {
var results = [Int]()
for number in numbers {
// 调用可能抛出错误的闭包
let processed = try closure(number)
results.append(processed)
}
return results
}
// 闭包不抛出错误时,调用不需要 try
let safeNumbers = [1, 2, 3]
let doubled = processNumbers(safeNumbers) { $0 * 2 } // 直接调用,无需 try
print(doubled) // 输出 [2, 4, 6]
// 闭包抛出错误时,调用需要 try
do {
let result = try processNumbers([1, -2, 3]) { num in
guard num >= 0 else {
throw NetworkError.requestFailed // 闭包抛出错误
}
return num * 2
}
} catch {
print("捕获错误: \(error)") // 输出错误
}
3. throws vs rethrows 的区别
| 特性 | throws | rethrows |
|---|---|---|
| 错误来源 | 函数自身或内部闭包 | 仅来自传入的闭包参数 |
是否必须用 try | 总是需要处理错误 | 仅在闭包抛出错误时需要 try |
| 典型应用场景 | 任意可能抛出错误的函数 | 高阶函数(如 map、filter) |
| 函数自身能否抛错 | 可以 | 不能,只能传递闭包的错误 |
4. 深入理解 rethrows
规则:
rethrows函数必须接受至少一个throws闭包作为参数。- 函数内部不能直接抛出自己的错误,只能传递闭包的错误。
Swift 标准库中的 rethrows:
// Swift 标准库的 map 函数声明
func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
- 当
transform闭包无错误时,map可直接调用:[1, 2, 3].map { $0 * 2 } // 无需 try - 当
transform闭包有错误时,必须处理:try [1, 2, 3].map { num in guard num > 0 else { throw NetworkError.requestFailed } return num * 2 }
5. 总结与最佳实践
- 使用
throws:当函数自身逻辑可能抛出错误时。 - 使用
rethrows:当函数是接受闭包的高阶函数,且错误仅来自闭包时。 - 灵活组合:结合
try、try?、try!和do-catch实现精细的错误处理。
通过合理使用 throws 和 rethrows,可以编写更安全、灵活的 Swift 代码!