欢迎关注微信公众号「Swift 花园」
数组
数组是用于存储一组值的合集。举个例子,红、绿、蓝是三基色,你可以对它们进行调和从而产生新颜色。因此颜色就可以用一个包含了红、绿、蓝三个值的数组来存储。
代码上,我们这么书写:
1 | let red = 1.0 |
上面的最后一行代码创建了一个数组:它以方括号开始和结束,里面的元素通过逗号分隔。
你可以通过书写数组名加上内部包含一个数字的方括号来读取数组里的元素。注意:这个数字代表元素在数组里的位置,几乎在所有的计算机编程语言中,这个位置都是从 0
开始的。所以,如果你想读取蓝色,可以这么写:
1 | color [2] |
小心:如果你尝试读取一个不存在的值, Swift 将会崩溃。例如,试图读取 color [5]
就不是一个好主意。
另外还要注意的是,如果你想使用类型注解,数组是通过方括号加里面的类型来表示的: [String]
,[Int]
,[Double]
和 [Bool]
。
集合
集合跟数组类似,也是存储一组值的合集。但它们有两个区别:集合中的元素是随机存放的,而数组中的元素是顺序存放的。集合中不允许有两个相同的元素,即任何一个元素只能出现一次。数组则没有这个限制。
你可以直接利用数组来创建一个集合,就像这样:
1 | let colors = Set(["red", "green", "blue"]) |
当你在 Playground 中查看 colors 中的元素时,你看到的元素的顺序可能跟你创建 colors 时填写的顺序不同。实际上,这个顺序并非真的是每次都随机生成,只不过很有可能跟你给的顺序不同。
Swift 内部自有算法来生成这个顺序,但不保证跟你创建集合时传入的顺序一致。所以,通过位置来读取数组中的元素那种方式,对于读取集合中的元素是不适用的。
如果你试图往集合中插入一个已经存在的元素,重复的这个元素会被忽略。举个例子:
1 | let colors2 = Set(["red", "green", "blue", "red", "blue"]) |
最后的 colors2
只会包含 red
,green
和 blue
各一个。
元组
元组允许你通过一个值来存储几个值。 听起来跟数组很像,但元组有所不同:你不能往元组中添加或者删除元素 —— 元组的长度是固定的。你不能改变元组中元素的类型 —— 元组创建时内部的元素类型必须是一致的。
你可以通过位置或者名称来访问元组中的元素。但是 Swift 不允许你访问不存在的位置或者名称。
元组的创建方式是把一组值放进圆括号中,就像这样:
1 | var name = (first: "Taylor", last: "Swift") |
你可以通过从 0 之类的位置信息来访问元组的元素:
1 | name.0 |
或者你也可以通过名称来访问元组的元素:
1 | name.first |
在元组创建之后,你可以改变其中元素的值,但是不能改变它们的类型。因此,如果你尝试把 name 改成 (first: “韩梅梅”,age: 25) ,将会遭遇错误。
数组 vs 集合 vs 元组
数组,集合和元组第一眼看上去很相似,但它们的用途是有区别的。为了帮助你更好地选择,这里有一些规则供参考:
如果你需要存放的元素是关联在一起被使用的,它们的个数固定,顺序或者名称也相对固定,那么你应当使用元组。举个例子:
1 | let address = (门牌号: 666, 街道: " 朝阳区某街道 & quot;, 城市: " 北京 & quot;) |
如果你需要一个合集,其中的元素必须是唯一的,或者你可能需要快速地检验合集里有没有包含某个元素,那么你应当使用集合。
1 | let shoppingList = Set([" 苹果 & quot;, " 肉 & quot;, " 牛奶 & quot;]) |
如果你需要一个合集,其中的元素允许重复,或者合集中元素的顺序对你来说很重要,那么你应当使用数组。
1 | let pingpongScores = ["11-7", "8-11", "11-9", "8-11", "11-5", "13-11"] |
三种类型中,数组是最常用的。
字典
字典也是用于存储一组值的合集。但跟数组用整数的位置来访问元素的方式不同的是,在字典里你可以用任何你想要的类型来充当访问标识。
当然,最常见的存储字典的访问标识是字符串。举个例子,我们可以创建一个基于运动员的名字来访问运动员的身高的字典:
1 | let top3NBAHeights = [ |
就像数组一样,字典也以方括号开始和结束,里面的元素通过逗号分隔。此外,为了把一个值(例如 2.28)存放到对应的标识(例如 “姚明”)下面,你还得用到一个冒号。
这些访问标识被称为 “键”,相对应的是 “值”。我们用键来读取值。
1 | top3NBAHeights [" 姚明 & quot;] |
注意:如果你想使用类型注解,数组是通过方括号加里面的键值对类型来表示的,键值对又通过冒号分隔。举个例子, [String: Double]
或者 [String: String]
。
字典默认值
如果你试图通过一个不存在于字典中的键读取字典中的值时, Swift 会返回给你一个 nil 。它代表没有东西。当然,这可能就是你想要 Swift 在找不到目标时返回给你的结果。不过,我们还有另外一种选择:当给定的键对应的值不存在时,我们可以指定一个默认的值返回给访问者。
为了演示这种操作,我们先创建一个包含了两个人最喜欢的冰淇淋的字典:
1 | let favoriteIceCream = [ |
我们可以像这样读取小明最喜欢的冰淇淋:
1 | favoriteIceCream [" 小明 & quot;] |
但是当我们试图读取小华最喜欢的冰淇淋时,我们会得到一个 nil ,这代表 Swift 没有在字典里找到对应 “小华” 这个键的值。
1 | favoriteIceCream [" 小华 & quot;] |
这种情况下,我们可以通过指定一个默认值,比如说 “未知”,来解决这个问题。这样做之后, 当 Swift 没有从字典中找到小华最喜欢的冰淇淋时,我们得到的不再是一个 nil ,而是一个 “未知” 字符串。
1 | favoriteIceCream [" 小华 & quot;, default: " 未知 & quot;] |
创建空的合集
数组,集合和字典都属于合集,因为它们都是把分散的值收集起来放在一处的结构。
如果你想要创建一个空的合集,只需要写上类型名,然后加上一组圆括号。举个例子,创建一个键和值的类型都是 String
的字典,我们可以这样书写:
1 | var teams = [String: String]() |
之后添加元素,就像这样:
1 | teams [" 小红 & quot;] = " 红色 & quot; |
类似的,你可以像这样创建一个 Int
类型的空数组:
1 | var results = [Int]() |
创建集合是一个例外,方式稍有不同:
1 | var words = Set<String>() |
这是因为 Swift 只为字典和数组提供了特殊的语法,其他类型都必须使用尖括号来声明类型信息,就像集合那样。
当然,也可以不使用特殊语法,通过和集合类似的标准方式创建字典和数组:
1 | var scores = Dictionary<String, Int>() |
枚举
枚举,通常简称 enums
,是一种定义一组高度关联的值的方式。它使得这组关联的值使用起来更方便。为什么这么说呢?
想象一下,如果你想要写一些代码表示正在做的某件事情的结果,成功或者失败,你选择了使用字符串来表示这个结果:
1 | let result = "failure" |
不过,有人不小心写错了或者采用了不同的拼写,就像下面这样:
1 | let result2 = "failed" |
上面几行表示失败的字符串都各不相同,所以它们代表不一样的东西,无法让你基于失败这一结果的代码被正确执行。
而有了枚举,我们可以定义一个叫做 Result
的类型,它既可以是 success
,也可以是 failure
,就像这样:
1 | enum Result { |
现在,当我们再想要表示结果时,只需要从两个值中选择一个:
1 | let result4 = Result.failure |
这样做的好处是可以避免书写不一致字符串导致跟预期不匹配的情况发生。
枚举关联值
除了可以存储简单的值,枚举还可以存储附属于每个 case
的关联值。这个特性使得你可以为枚举附加额外的数据,从而让它们传达更多细微的信息。
举个例子,我们可以定义一个枚举,它存放了各种各样的活动类型:
1 | enum Activity { |
上面的枚举类型存储的信息,可以让我们知道有人在讲话,但我们不知道讲话的内容,或者可以让我们知道有人在跑步,但我们不知道他们将跑去哪里。
通过枚举的关联值,我们添加额外的细节:
1 | enum Activity { |
现在我们有了更精确的信息。我们可以说某人正在谈论足球:
1 | let talking = Activity.talking (topic: "football") |
枚举原始值
有的时候你可能想给枚举赋予一些原始值从而让它们可以表达某种含义。这么做可以让你动态地创建枚举,并且以不一样的方式来使用它们。
举个例子,你可以创建一个名叫 Planet
的枚举,然后让它的每条 case 存储一个整数:
1 | enum Planet: Int { |
Swift 会为这些 case 自动分配一个数字,同样的,是从 0 开始。你可以利用这些数字创建枚举的 case 。举个例子, earth
会被分配到数字 2 ,于是你可以这么创建一个 earth
的 case :
1 | let earth = Planet(rawValue: 2) |
如果你自行指定了一个或者几个 case 的原始值, Swift 可能会自动为剩下的 case 生成原始值,只要这些值是可以被 Swift 推断的。比如把地球算作第 2 颗行星来考虑可能不太自然(因为我们一般说它是九大行星中的第 3 颗),于是你可以这么写:
1 | enum Planet: Int { |
这样一来 Swift 就会给 mercury
分配数字 1 ,后面的数字基于前面的往上加, earth
就变成第 3 颗行星了。
总结
让我们来总结一下。
- 数组,集合,元组和字典让你可以通过单一对象存储一组值。它们实现这一点的方式各有不同,所以你需要根据具体场景来决定采用哪一种结构。
- 数组按顺序存储数据,你可以往里面添加或者删除元素,并通过位置来读取。
- 集合不按顺序存储数据,所以你不能通过位置来访问,但它提供了元素不重复的特性。
- 元组长度固定,你可以给里面的每个元素取名。这样就既可以通过位置,也可以通过名字来读取。
- 字典根据键来存储数据,因此读取元素时要用到键。
- 枚举是一种分组关联值的方法,帮你避免拼写错误。
- 你可以为枚举的每条
case
设置原始值,同时还可以为它们附加关联值来提供额外的信息。