【问题标题】:Nested do catch swift 3.0嵌套 do catch swift 3.0
【发布时间】:2018-01-22 04:16:57
【问题描述】:

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

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

【问题讨论】:

  • do 中执行所有try 语句,并在catch 中捕获任何异常。根本不需要嵌套它们。
  • 如果 OP 只想在 firstThing 失败时运行第二件事并在 secondThing 失败时运行thirdThing,这将不起作用@Pancho。
  • 感谢@Pancho,但由于我要返回值(或错误),任何代码都不会执行第一次返回。
  • @Abizern 这是真的。在这种情况下,必须用 if-else 或 switch 语句替换 do-catch,这不会减少代码或使其更漂亮。
  • 为什么投反对票?

标签: swift error-handling do-catch


【解决方案1】:

如果不需要从这些函数调用中抛出的实际错误 然后您可以使用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())

【讨论】:

  • 我只需要最后一个错误,所以这应该可以完成工作。谢谢。
  • 这可以适用于 void 函数吗?
  • @Deco: 当然,(try? firstThing()) ?? (try? secondThing()) ?? (try thirdThing()) 会依次调用函数,直到没有抛出。
【解决方案2】:

如果 Martin 的回答对您来说过于简洁,您可以使用单独的 catch 块。

do {
    return try firstThing()
} catch {}

do {
    return try secondThing()
} catch {}

do {
    return try thirdThing()
} catch {}

return defaultThing()

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

【讨论】:

  • 酷,这解决了它而无需转换为可选项。谢谢尼古拉。
【解决方案3】:

另一种方法是编写一个将所有抛出函数作为参数的函数。它返回第一个成功执行的或 nil。

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

lazy 确保仅在找到第一个匹配项之前调用这些值。这样做,你也可以很快的添加很多case。

你可以这样使用函数

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

我还包含了我用来在 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"

【讨论】:

    猜你喜欢
    • 2015-08-23
    • 1970-01-01
    • 2016-05-27
    • 2016-05-21
    • 2017-12-02
    • 2017-02-28
    • 1970-01-01
    • 2016-09-30
    • 2020-01-15
    相关资源
    最近更新 更多