嵌套式抓捕swift 3.0

嵌套式抓捕swift 3.0,swift,error-handling,do-catch,Swift,Error Handling,Do Catch,我想使用连续的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合并运算符
??
链接调用

例如:

if let result = (try? firstThing()) ?? (try? secondThing()) ?? (try? thirdThing()) {
    return result
} else {
    // everything failed ...
}
或者,如果最后一个方法的错误应该在所有操作都失败时抛出, 对除最后一个方法调用以外的所有方法调用使用
try?

return (try? firstThing()) ?? (try? secondThing()) ?? (try thirdThing())

如果马丁的回答对你的口味来说过于简练,你可以选择单独的抓块

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
}
我还包括了我用来在操场上测试的代码:

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"
enum ThingError:错误{
案例零
}
func firstThing()抛出->字符串{
打印(“0”)
扔掉那个东西
返回“0”
}
func secondThing()抛出->字符串{
打印(“1”)
返回“1”
}
func thirdThing()抛出->字符串{
打印(“2”)
返回“B”
}
func first(u值:(()抛出->T)…)->T?{
返回值.lazy.flatMap({(throwingFunc)->T?in
返回try?throwingFunc()
}).首先
}
func tryThings()->字符串{
返回第一项(第一项、第二项、第三项)??“默认”
}
tryThings()//打印“0”和“1”

执行
中的所有
尝试
语句,并捕获
捕获中的任何异常。根本不需要嵌套它们。如果OP只想在第一件事失败时运行第二件事,而在第二件事失败时运行第三件事,那么@Pancho将不起作用。谢谢@Pancho,但由于我返回值(或错误),任何代码都不会执行第一次返回。@Abizern这是真的。在这种情况下,do-catch必须被if-else或switch语句替换,这不会减少代码或使其变得美观。为什么要进行向下投票?我只需要最后一个错误,所以这应该可以完成工作。谢谢。这能适应void函数吗?@Deco:当然,
(试试?firstThing())??(试试?第二件事())??(试试thirdThing())
依次调用函数,直到没有抛出为止。很酷,这可以解决问题,而无需转换为optionals。谢谢你,尼古拉。
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"