我想使用连续的 try 语句。如果一个返回错误,我想继续下一个,否则返回值。下面的代码似乎工作正常,但是我最终会得到一个大的嵌套 do catch 金字塔。在 Swift 3.0 中有更聪明/更好的方法吗?
do {
return try firstThing()
} catch {
do {
return try secondThing()
} catch {
return try thirdThing()
}
}
我想使用连续的 try 语句。如果一个返回错误,我想继续下一个,否则返回值。下面的代码似乎工作正常,但是我最终会得到一个大的嵌套 do catch 金字塔。在 Swift 3.0 中有更聪明/更好的方法吗?
do {
return try firstThing()
} catch {
do {
return try secondThing()
} catch {
return try thirdThing()
}
}
如果不需要从这些函数调用中抛出的实际错误,则可以使用try?
将结果转换为可选项,并使用 nil-coalescing 运算符链接调用??
。
例如:
if let result = (try? firstThing()) ?? (try? secondThing()) ?? (try? thirdThing()) {
return result
} else {
// everything failed ...
}
或者,如果在一切都失败的情况下应该抛出最后一个方法的错误,请使用try?
除最后一个方法调用之外的所有方法:
return (try? firstThing()) ?? (try? secondThing()) ?? (try thirdThing())
如果 Martin 的回答对您的口味来说太简洁,您可以使用单独的 catch 块。
do {
return try firstThing()
} catch {}
do {
return try secondThing()
} catch {}
do {
return try thirdThing()
} catch {}
return defaultThing()
由于每个抛出函数的结果都会立即返回,因此不需要嵌套。
另一种方法是编写一个将所有抛出函数作为参数的函数。它返回第一个成功执行的或 nil。
func first<T>(_ values: (() throws -> T)...) -> T? {
return values.lazy.flatMap({ (throwingFunc) -> T? in
return try? throwingFunc()
}).first
}
惰性确保仅在找到第一个匹配项之前调用这些值。这样做,您还可以非常快速地添加很多案例。
您可以像这样使用该功能
return first(firstThing, secondThing, thirdThing) ?? "Default"
我还包括了我用来在操场上测试它的代码:
enum ThingError: Error {
case zero
}
func firstThing() throws -> String {
print("0")
throw ThingError.zero
return "0"
}
func secondThing() throws -> String {
print("1")
return "1"
}
func thirdThing() throws -> String {
print("2")
return "B"
}
func first<T>(_ values: (() throws -> T)...) -> T? {
return values.lazy.flatMap({ (throwingFunc) -> T? in
return try? throwingFunc()
}).first
}
func tryThings() -> String {
return first(firstThing, secondThing, thirdThing) ?? "Default"
}
tryThings() // prints "0" and "1"