处理Swift中类函数内部错误时的非穷举列表

时间:2017-03-30 06:12:56

标签: swift

在游乐场/项目中运行以下代码段:

class Piece {
    enum ParseError: Error {
        case unknown(string: String)
    }

    class func parse(string: String) throws {
        throw ParseError.unknown(string: string)
    }
}

class Board {
    class func parse(string: String) {
        do {
            try Piece.parse(string: string)
        } catch Piece.ParseError.unknown(let string) {
            print(string)
        }
    }
}

提供 Swift编译器错误

  

由于封闭的捕获并非详尽无法处理,因此不会处理从此处抛出的错误

以下工作正常:

enum ParseError: Error {
    case unknown(string: String)
}

func parse(string: String) throws {
    throw ParseError.unknown(string: string)
}

do {
    try parse(string: "rook")
} catch ParseError.unknown(let string) {
    print(string)
}

运行Xcode 8.3 / Swift 3.1

错误的原因是什么?

2 个答案:

答案 0 :(得分:2)

作为said by the language guide(强调我的):

  

do子句不必处理其catch子句中的代码可能抛出的每个可能的错误。如果class Board { class func parse(string: String) { do { try Piece.parse(string: string) } catch Piece.ParseError.unknown(let string) { print(string) } } } 子句都没有处理错误,则错误会传播到周围的范围。 但是,错误必须由某些周边范围处理 [...]

因此,你的例子

Piece.parse(string: string)

是非法的 - 因为合并后,do-catch块和封闭范围(实际方法本身)不会彻底处理Error可能抛出的每个可能错误(请记住,抛出函数可以抛出符合do { try Piece.parse(string: string) } catch Piece.ParseError.unknown(let string) { print(string) } catch { // do error handling for any miscellaneous errors here. print(error) } 协议的任何错误类型。

你要么想要添加一个"赶上所有"阻止你的do-catch以处理任何其他抛出的错误:

parse(string:)

或者使class func parse(string: String) throws { // ... } 成为一种投掷方法,以便将任何未捕获的错误传播回调用者。

enum ParseError: Error {
    case unknown(string: String)
}

func parse(string: String) throws {
    throw ParseError.unknown(string: string)
}

do {
    try parse(string: "rook")
} catch ParseError.unknown(let string) {
    print(string)
}

唯一的原因

fatalError()

main.swift文件的顶层进行编译只是因为该范围很特殊。它可以捕获任何未被捕获的错误,并且在执行此操作时将调用/// Invoked by the compiler when code at top level throws an uncaught error. @_silgen_name("swift_errorInMain") public func _errorInMain(_ error: Error) { fatalError("Error raised at top level: \(String(reflecting: error))") } 以及该错误的描述。

我找不到任何官方文档,但是如果你查看标准库的ErrorType.swift文件,你会看到以下功能:

swift_errorInMain

如果我们examine the IR emitted获得上述代码的简化版本,我们可以确定编译器在发生未被捕获的错误时会插入对swiftc的调用。

使用游乐场,您会得到类似的行为,因为编译器允许在顶层发生未被捕获的错误 - 尽管在抛出错误的情况下,游乐场似乎无声地终止而不显示致命的错误消息。 / p>

由于Swift playground在他们自己的特殊环境中运行代码这一事实很难进一步调查,因此意味着运行时行为与使用echo编译的代码有很大不同。实际上,你不应该使用游乐场来测试Swift代码的实际行为。

答案 1 :(得分:1)

看看这个答案:

  

"因为你的函数无法说明它会抛出什么样的错误(或者将来可能抛出的错误),捕获错误的catch块不知道它可能会出现什么类型的错误扔。因此,除了处理你所知道的错误类型之外,还需要处理那些你没有使用通用catch语句的错误类型 - 这样如果你的函数改变了它将来抛出的错误集,调用者将会仍然抓住它的错误。"

https://stackoverflow.com/a/30720807/6203030

在您的情况下,可以通过添加以下内容来解决此问题:

class Board {
    class func parse(string: String) {
        do {
            try Piece.parse(string: string)
        } catch Piece.ParseError.unknown(let string) {
            print(string)
        } catch let error {
            print(error.localizedDescription)
        }
    }
}

您需要捕获所有错误。