Swift do-try-catch语法

mus*_*afa 157 swift swift2

我尝试了解swift 2中的新错误处理事情.这是我做的:我首先声明了一个错误枚举:

enum SandwichError: ErrorType {
    case NotMe
    case DoItYourself
}
Run Code Online (Sandbox Code Playgroud)

然后我宣布了一个抛出错误的方法(不是一个例外的人.这是一个错误.).这是方法:

func makeMeSandwich(names: [String: String]) throws -> String {
    guard let sandwich = names["sandwich"] else {
        throw SandwichError.NotMe
    }

    return sandwich
}
Run Code Online (Sandbox Code Playgroud)

问题来自呼叫方.以下是调用此方法的代码:

let kitchen = ["sandwich": "ready", "breakfeast": "not ready"]

do {
    let sandwich = try makeMeSandwich(kitchen)
    print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
    print("Not me error")
} catch SandwichError.DoItYourself {
    print("do it error")
}
Run Code Online (Sandbox Code Playgroud)

do行编译器说完之后Errors thrown from here are not handled because the enclosing catch is not exhaustive.但在我看来,这是详尽的,因为在SandwichError枚举中只有两个案例.

对于常规的switch语句,swift可以理解它在处理每个案例时都是详尽无遗的.

ric*_*ter 259

Swift 2错误处理模型有两个重点:穷举和弹性.总之,他们归结为你的do/ catch声明需要捕捉每一个可能的错误,而不仅仅是你知道你可以抛出的错误.

请注意,您没有声明函数可以抛出哪些类型的错误,只是它是否会抛出.这是一个零无限的问题:当有人为其他人(包括你未来的自我)定义一个函数时,你不希望让你的函数的每个客户都适应你的实现中的每一个变化.功能,包括它可以抛出的错误.您希望调用函数的代码能够适应这种变化.

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

do {
    let sandwich = try makeMeSandwich(kitchen)
    print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
    print("Not me error")
} catch SandwichError.DoItYourself {
    print("do it error")
} catch let error {
    print(error.localizedDescription)
}
Run Code Online (Sandbox Code Playgroud)

但是,我们不止于此.再考虑一下这种弹性想法.你设计三明治的方式,你必须在你使用它们的每个地方描述错误.这意味着无论何时更改错误案例集,您都必须更改使用它们的每个地方......不是很有趣.

定义自己的错误类型背后的想法是让你集中这样的事情.您可以description为错误定义方法:

extension SandwichError: CustomStringConvertible {
    var description: String {
        switch self {
            case NotMe: return "Not me error"
            case DoItYourself: return "Try sudo"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后您的错误处理代码可以要求您的错误类型来描述自己 - 现在您处理错误的每个地方都可以使用相同的代码,并处理可能的未来错误情况.

do {
    let sandwich = try makeMeSandwich(kitchen)
    print("i eat it \(sandwich)")
} catch let error as SandwichError {
    print(error.description)
} catch {
    print("i dunno")
}
Run Code Online (Sandbox Code Playgroud)

这也为错误类型(或它们的扩展)铺平了道路,以支持报告错误的其他方式 - 例如,您可以在错误类型上拥有一个扩展,知道如何向UIAlertControlleriOS用户报告错误.

  • 喜欢你如何在扩展中分离错误消息.非常好的方法来保持你的代码干净!好例子! (5认同)

Sam*_*Sam 28

我怀疑这还没有正确实施.在斯威夫特编程指南肯定似乎暗示编译器可以推断出详尽的比赛就像一个switch语句".它没有提及需要通用catch以便详尽无遗.

您还会注意到错误是try在行上,而不是块的结尾,即在某些时候编译器将能够确定try块中的哪个语句具有未处理的异常类型.

但是文档有点含糊不清.我已经浏览了"Swift中的新内容"视频,但找不到任何线索; 我会继续努力.

更新:

我们现在已经达到Beta 3,没有提示ErrorType推断.我现在相信,如果这是有计划的(我仍然认为它在某个时候),协议扩展的动态调度可能会将其扼杀.

Beta 4更新:

Xcode 7b4添加了doc comment支持Throws:,"应该用于记录可以抛出的错误以及为什么".我想这至少提供了一些机制来向API消费者传达错误.有文档时谁需要类型系统!

另一个更新:

花了一些时间希望自动ErrorType推理,并弄清楚该模型的局限性,我改变了主意 - 是我希望Apple实现的.实质上:

// allow us to do this:
func myFunction() throws -> Int

// or this:
func myFunction() throws CustomError -> Int

// but not this:
func myFunction() throws CustomErrorOne, CustomErrorTwo -> Int
Run Code Online (Sandbox Code Playgroud)

又一次更新

现在可以在此处获得Apple的错误处理原理.关于swift-evolution邮件列表也有一些有趣的讨论.从本质上讲,John McCall反对输入错误,因为他认为大多数库最终会包含一般错误情况,并且除了样板之外,类型错误不太可能对代码增加太多(他使用术语'有抱负的虚张声势').Chris Lattner表示,如果可以使用弹性模型,他可以在Swift 3中输入错误.