在游乐场/项目中运行以下代码段:
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
错误的原因是什么?
答案 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)
}
}
}
您需要捕获所有错误。