Swift 3.0中的嵌套do catch

14
我想使用连续的try语句。如果一个返回错误,我想继续下一个,否则返回值。 下面的代码似乎工作正常,但最终会得到一个大的嵌套的do catch金字塔。在Swift 3.0中有没有更聪明/更好的方法来做到这一点?

我想使用连续的try语句。如果一个返回错误,我想继续下一个,否则返回值。 下面的代码似乎能够很好地工作,但是我将会得到一个庞大的嵌套式的do-catch金字塔。在Swift 3.0中,是否有更加聪明和更好的方法来完成这个任务?

do {
    return try firstThing()
} catch {
    do {
        return try secondThing()
    } catch {
        return try thirdThing()
    }
}

3
将所有的try语句放在do块中,并在catch中捕获任何异常。完全不需要嵌套它们。 - Pancho
3
如果原帖作者只想在第一件事情失败时运行第二件事情,并且在第二件事情失败时运行第三件事情,那么@Pancho的解决方法行不通。 - Abizern
谢谢@Pancho,但是由于我正在返回值(或错误),任何代码中的第一个返回将不会被执行。 - Mymodo
@Abizern 这是真的。在这种情况下,必须用 if-else 或 switch 语句替换 do-catch,这不会减少代码或使其更美观。 - Pancho
5
为什么会有踩的反对票? - Nikolai Ruhe
3个回答

17
如果不需要从这些函数调用中抛出实际错误,那么可以使用 try? 将结果转换为可选项,并使用空合并运算符 ?? 链接调用。
例如:
if let result = (try? firstThing()) ?? (try? secondThing()) ?? (try? thirdThing()) {
    return result
} else {
    // everything failed ...
}

或者,如果在所有方法都失败时应该抛出上一个方法的错误,请对除最后一个方法调用之外的所有方法使用try?:

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

我只需要最后一个错误,所以这应该可以完成工作。谢谢。 - Mymodo
这个能适用于无返回值函数吗? - Declan McKenna
1
@Deco:当然,(try? firstThing()) ?? (try? secondThing()) ?? (try thirdThing()) 会依次调用这些函数,直到其中一个不抛出异常。 - Martin R

17

如果马丁的回答对您来说太简短了,您可以选择每个捕获块。

do {
    return try firstThing()
} catch {}

do {
    return try secondThing()
} catch {}

do {
    return try thirdThing()
} catch {}

return defaultThing()

每个抛出函数的结果都会立即返回,因此不需要嵌套。


很棒,这样就不用转换为可选项了。谢谢Nikolai。 - Mymodo

4

另一种方法是编写一个函数,将所有的throwing函数作为参数传递给它。它返回成功执行的第一个函数,如果没有,则返回nil。

func first<T>(_ values: (() throws -> T)...) -> T? {
    return values.lazy.flatMap({ (throwingFunc) -> T? in
        return try? throwingFunc()
    }).first
}

lazy 函数确保值只在找到第一个匹配项之前被调用。通过这种方式,您也可以快速地添加许多案例。

您可以像这样使用该函数

return first(firstThing, secondThing, thirdThing) ?? "Default"

我还在playground中包括了我用来测试的代码:

我还在playground中包括了我用来测试的代码:

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"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接