前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Swift中的模式匹配

Swift中的模式匹配

作者头像
小刀c
发布2022-09-21 16:51:17
1.7K0
发布2022-09-21 16:51:17
举报
文章被收录于专栏:cc logcc log

Swift 作为一门现代语言,除去安全,快速等特性之外,还有个明显有别于其他语言的特性,就是巨量细致入微的语言特性。类似iOS API,初学者觉得繁杂,无从下手,但是熟悉之后,绝对能少写不少代码。

其中强大的模式匹配绝对让你用的很爽。

主要整理自:pattern-matching-in-swift

迭代器中

我们经常会在for循环中,使用if判断。

代码语言:javascript
复制
func deleteMarkedMessages() {
    for message in messages {
        if message.isMarked {
            database.delete(message)
        }
    }
}

上面绝对能工作,你可能会使用函数式的写法。

代码语言:javascript
复制
func deleteMarkedMessages() {
    messages.filter { $0.isMarked }
            .forEach(database.delete)
}

上述可能需要团队熟悉函数式编程,而且整个数组会经过两遍处理。

而Swift中where判断,则是此类情况的绝佳解决方案。

代码语言:javascript
复制
func deleteMarkedMessages() {
    for message in messages where message.isMarked {
        database.delete(message)
    }
}

而对于Swift Optional数据来说,例如类似的数据结构:

代码语言:javascript
复制
struct Match {
    var startDate: Date
    var players: [Player?]
}

假设我们需要循环players,且需要排除nil的值,我们可以使用传统的if判断,或者使用函数式的,compactMap函数。但是在Swift中有个更高阶的方法,使用for case let语法。

代码语言:javascript
复制
func makePlayerListView(for players: [Player?]) -> UIView {
    let view = PlayerListView()

    for case let player? in players {
        view.addEntryForPlayer(named: player.name,
                               image: player.image)
    }

    return view
}

这个乍看很奇怪,一般只会在switchenum声明中才能看到case。但是实际上,swift中optional值底层是Optional<Wrapped>的枚举enum,而且swift的模式匹配不是只在switch下才能工作。

switch中的optional可选判断

例如如下的enum,

代码语言:javascript
复制
enum LoadingState {
    case loading
    case failed(Error)
}

在无状态的情况下,我们使用可选optional的LoadingState?,在switch匹配中,我们同样可以将? 使用在case的情况,以此来匹配有值的情况。

代码语言:javascript
复制
extension ContentViewController: ViewModelDelegate {
    func viewModel(_ viewModel: ViewModel,
                   loadingStateDidChangeTo state: LoadingState?) {
        switch state {
        case nil:
            removeLoadingSpinner()
            removeErrorView()
            renderContent()
        case .loading?:
            removeErrorView()
            showLoadingSpinner()
        case .failed(let error)?:
            removeLoadingSpinner()
            showErrorView(for: error)
        }
    }
}

声明式的错误处理

错误处理,特别是http错误处理通常挺复杂的,一大堆if else代码。而在swift的强大的模式匹配下,我们可以写出声明式的代码。

代码语言:javascript
复制
func handle(_ error: Error) {
    switch error {
    // Matching against a group of offline-related errors:
    case URLError.notConnectedToInternet,
         URLError.networkConnectionLost,
         URLError.cannotLoadFromNetwork:
        showOfflineView()
    // Matching against a specific error:
    case let error as HTTPError where error == .unauthorized:
        logOut()
    // Matching against our networking error type:
    case is HTTPError:
        showNetworkErrorView()
    // Fallback for other kinds of errors:
    default:
        showGenericErrorView(for: error)
    }
}

模式匹配底层逻辑,以及自定义模式匹配

 Swift中模式匹配部分依赖变量相关语法(例如case let), 这里值和模式匹配的真正逻辑并没有到编译那一步,甚至也不是语言语法,类似很多貌似“底层”的特性其实是在标准库中通过常规的Swift 代码来实现。

具体,Swift使用重载~=运算符号来实现模式匹配——这也就就给了我们自定义模式匹配的方法。

类似上面的判断错误,使用~=运算符号重载

代码语言:javascript
复制
func ~=<E: Error & Equatable>(rhs: E, lhs: Error) -> Bool {
    return (lhs as? E) == rhs
}

这样,上述的switch case写起来更简洁。

代码语言:javascript
复制
func handle(_ error: Error) {
    switch error {
    case URLError.notConnectedToInternet,
         URLError.networkConnectionLost,
         URLError.cannotLoadFromNetwork:
        showOfflineView()
    case HTTPError.unauthorized:
        logOut()
    case is HTTPError:
        showNetworkErrorView()
    default:
        showGenericErrorView(for: error)
    }
}

swift 模式匹配很强大,无疑会减少不少代码,不过里面高级的玩法确实看起来容易费解,这点可能就是swift 这门语言让人又爱又恨的地方。

从我角度来说,我喜欢这种复杂度,可玩性更高~^-^~。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 迭代器中
  • switch中的optional可选判断
  • 声明式的错误处理
  • 模式匹配底层逻辑,以及自定义模式匹配
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档