Swift 初级码农趣谈:如何优雅的在 for...in 循环中解包可选值?

142 阅读3分钟

在这里插入图片描述

概述

在 Swift 撸码进行曲中,我们经常要做的“功”就是将可选值解包(unwrap)。这样一种简单的不能再简单的操作,稍有不慎也会横生枝节,让初学秃头小码农们焦头烂额。

在这里插入图片描述

不过别担心,只要稍加囊萤映雪我们也能唱着郭美美“不怕不怕啦”的动人旋律,走上人生巅峰。

在本篇博文中,您将学到如下内容:

  1. 一次解包(unwrap)可选值的小挫折
  2. 查无此“人”:for...in 中 where 的“局限”
  3. 快使用 compactMap
  4. 少有人走的路:case let

相信学完本课后,各位初学 Swift 的小剑客们必定对可选值的解包操作胸有成竹,游刃有余!

那还等什么呢?Let‘s go!!!;)


1. 一次解包(unwrap)可选值的小挫折

各位初学 Swift 的小伙伴们自然都了然如何解包可选值,这真是简单的不要不要的。但是如果我们遍历序列的元素都是可选值,大家又如何应对呢?

var ary: [Int?] = [1, nil, 2, 5, nil, nil, 11, nil]

for number in ary {
    print("\(number)")
}

如上代码所示,我们用 for...in 循环语句遍历了一个满是 Int? 可选值的数组。不出所料,结果得到的都是可选值:

Optional(1)
nil
Optional(2)
Optional(5)
nil
nil
Optional(11)
nil

如果我们需要在 for...in 循环中仅处理不为 nil 的数字,大家又有何良策呢?一种“中规中矩”的方法是不管三七二十一,“先遍历,再解包”:

for number in ary {
    if let number {
        print("\(number)")
    }
}

这样做可以达到目的,但结果仿佛有些庸人自扰:

在这里插入图片描述

2. 查无此“人”:for...in 中 where 的“局限”

大家是否记得,Swift 是一门极具现代化的语言,它为很多语句都添加了“旁路分支”来增加灵活性,比如 where 子句。

这在 for...in 语句中自然也不例外,我们可以通过 where 子句来为循环遍历的结果进一步添加限制:

for number in ary where number != nil {
    print("\(number)")
}

这样做可以起到一定过滤的效果。不过,这并不能改变每个遍历结果依旧是可选值的囧境:

Optional(1) Optional(2) Optional(5) Optional(11)

聪明的半秃小码农们可能觉得对 where 子句稍加修改便能迎刃而解:

for number in ary where let intNumber = number {
    print("\(intNumber)")
}

他们大概是想利用类似于 if let 中的语法来让 let 自动解包可选值。不幸的是,目前 Swift 6.0 中貌似还不支持这种 where 语法:

在这里插入图片描述

蛋疼么?没关系,周杰伦老师早就给出解决方案:嘿嘿哈嘿,快使用“compactMap”!

3. 快使用 compactMap

compactMap 是序列 map 方法的一个“变种”,它专门用于将可选值元素的序列转换为对应解包后值的序列:

在这里插入图片描述

于是乎,稍加变化我们即可得偿所愿:

for number in ary.compactMap({ $0 }) {
    print("\(number)")
}

在上面的代码中,我们利用序列上的 compactMap 方法将 nil 值统统消灭干净,只留下纯粹的世界:

在这里插入图片描述

4. 少有人走的路:case let

大家已经圆满的完成了任务,本来文章到这里就可以收尾了,可是我偏不!因为我们还有另一种“骚操作”:

for case let number? in ary {
    print("\(number)")
}

如上代码所示,我们在 for...in 循环中使用了 case let 语句,并在 let 收集的变量名称后面加上了一个问号,这绝对是画龙点睛之笔:这样做表示 number? 是一个可选值,那么 number 自然就不是一个可选值了!

运行可以发现,我们完美的达到了所需的效果,并且代码变得更加简洁了:

在这里插入图片描述

看到这里,小伙伴们一定顿悟到了什么,棒棒哒!💯

总结

在本篇博文中,我们讨论了如何在 Swift 的 for...in 循环遍历语句上做文章,妥妥地搞定了可选元素序列的解包问题。

感谢观赏,再会啦!8-)