MENU

Switch 新知

Cover

从概念提出以来 Switch 语法几乎是所有高级编程语言的标配,而 Swift 中的类型系统则进一步放大了它使用场景。正常情况下,我们会在对某个变量进行多状态判断时使用 Switch 语句。这样代码的控制流就与某一特定状态进行了绑定,同时代码也变得可读性强更易调试。

一个常见的简单示例就是对应用内用户的登录状态进行相应处理。if - else 模式的代码大致如下:

if user.isLoggedIn {
    showMainUI()
} else if let credentials = user.savedCredentials {
    performLogin(with: credentials)
} else {
    showLoginUI()
}

而如果将其替换为 enum 的话则会变成这样:

switch user.loginState {
    case .loggedIn:
        showMainUI()
    case .loggedOutWithSavedCredentials(let credentials):
        performLogin(with: credentials)
    case .loggedOut:
        showLoginUI()
}

这样做还有另一个好处,那就是我们能够在编译的时候确保不会遗漏任何状态,即使后期在 enum 类型中新增和修改都能全方位覆盖到。当然这只是 Switch 语法的常规操作而已,接下来将会介绍一些 Swift 中新的用法。

元组类型中应用

通过一个抽象的 Result 类型来表示多种类型的可能输出是当前的一个流行趋势。例如,在进行网络请求操作时返回的结果既可能成功也可能失败。以往针对这种请求我们一般可能会定义一个多参数的回调函数或者是一个包含所有可能的大型结构体,但是现在我们可以采用一种更为简便的方式:

enum Result {
    case success(Value)
    case error(Error)
}

接下来我们对其实现 Equatable 协议。实现方法多种多样,这里我介绍一种最为简单的方式:

extension Result: Equatable {
    static func ==(lhs: Result, rhs: Result) -> Bool {
        switch (lhs, rhs) {
        case (.success(let valueA), .success(let valueB)):
            return valueA == valueB
        case (.error(let errorA), .error(let errorB)):
            return errorA == errorB
        case (.success, .error):
            return false
        case (.error, .success):
            return false
        }
    }
}

与之前提到的一致,通过 swift 语句我们能够在编译器对 Result 类型的任何改变做出反应。

模式匹配

Swift 为人所熟知的另一项特点就是它强大的模式匹配能力,通过模式匹配我们可以很简单的就将上面定义的 Result 类型应用到常规的网络请求当中。

例如,当用户登录失效或者未激活时服务端会对所有的请求返回 401 未授权错误。此时我们可以通过模式匹配和 Switch 语法将结果处理从繁杂的 if-else 语句中解脱出来。

switch result {
case .success(let data):
    handle(data)
case .error(let error as HTTPError) where error == .unauthorized:
    logout()
case .error(let error):
    handle(error)
}

上面代码中通过模式匹配我们将 .unauthorized 错误安全的转为为了 HTTPError 类型,而其他错误也可以进一步通过 case 语句完成更细节的处理。

结语

虽然 if-else 语句也足以应付上面所提的这些情形,但是相比较而言 enum-switch 无论是编译器的支持以及可读性上来说都来的更有优势,所以我倾向于建议大家在日常编程中更多的使用后者。

标签: Swift, Switch