集合类型
Swift 语言提供数组(Array)、集合(Set)和字典(Dictionary)三种基本的集合类型用来存储集合数据。数组是有序数据的集。集合是无序无重复数据的集。字典是无序的键值对的集。
Swift 中的数组、集合和字典必须明确其中保存的键和值类型,这样就可以避免插入一个错误数据类型的值。同理,对于获取到的值你也可以放心,其数据类型是确定的。
注意
Swift 的数组、集合和字典类型被实现为泛型集合。
集合(Sets)
集合用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。
注意 Swift 的 Set 类型被桥接到 Foundation 中的 NSSet 类。
集合类型的哈希值
一个类型为了存储在集合中,该类型必须是可哈希化的——也就是说,该类型必须提供一个方法来计算它的哈希值。一个哈希值是 Int 类型的,相等的对象哈希值必须相同,比如 a == b,因此必须 a.hashValue == b.hashValue。
Swift 的所有基本类型(比如 String、Int、Double 和 Bool)默认都是可哈希化的,可以作为集合值的类型或者字典键的类型。没有关联值的枚举成员值默认也是可哈希化的。
注意
你可以使用自定义的类型作为集合值的类型或者是字典键的类型,但需要使自定义类型遵循 Swift 标准库中的 Hashable 协议。遵循 Hashable 协议的类型需要提供一个类型为 Int 的可读属性 hashValue。由类型的 hashValue 属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。
因为 Hashable 协议遵循 Equatable 协议,所以遵循该协议的类型也必须提供一个“是否相等”运算符()的实现。这个 Equatable 协议要求任何遵循 == 实现的实例间都是一种相等的关系。也就是说,对于 a,b,c 三个值来说, 的实现必须满足下面三种情况:
a == a(自反性)
a == b 意味着 b == a(对称性)
a == b && b == c 意味着 a == c(传递性)
集合类型语法
Swift 中的集合类型被写为 Set,这里的 Element 表示集合中允许存储的类型。和数组不同的是,集合没有等价的简化形式。
使用布尔属性 isEmpty 作为一个缩写形式去检查 count 属性是否为 0:
if favoriteGenres.isEmpty {
print("As far as music goes, I'm not picky.")
} else {
print("I have particular music preferences.")
}
// 打印“I have particular music preferences.”
数组(Array ),字典(Dictionary)写法变化,其他差不多。
控制流
Swift 提供了多种流程控制结构,包括可以多次执行任务的 while 循环,基于特定条件选择执行不同代码分支的 if、guard 和 switch 语句,还有控制流程跳转到其他代码位置的 break 和 continue 语句。
Swift 还提供了 for-in 循环,用来更简单地遍历数组(Array),字典(Dictionary),区间(Range),字符串(String)和其他序列类型。
Swift 的 switch 语句比许多类 C 语言要更加强大。case 还可以匹配很多不同的模式,包括范围匹配,元组(tuple)和特定类型匹配。switch 语句的 case 中匹配的值可以声明为临时常量或变量,在 case 作用域内使用,也可以配合 where 来描述更复杂的匹配条件。
For-In 循环
可以使用 for-in 循环来遍历一个集合中的所有元素,例如数组中的元素、范围内的数字或者字符串中的字符。
可以通过遍历一个字典来访问它的键值对。遍历字典时,字典的每项元素会以 (key, value) 元组的形式返回,你可以在 for-in 循环中使用显式的常量名称来解读 (key, value) 元组。下面的例子中,字典的键声明会为 animalName 常量,字典的值会声明为 legCount 常量:
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
// cats have 4 legs
// ants have 6 legs
// spiders have 8 legs
Switch
switch 语句会尝试把某个值与若干个模式(pattern)进行匹配。根据第一个匹配成功的模式,switch 语句会执行对应的代码。当有可能的情况较多时,通常用 switch 语句替换 if 语句。
不存在隐式的贯穿
与 C 和 Objective-C 中的 switch 语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止 switch 语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用 break 语句。这使得 switch 语句更安全、更易用,也避免了漏写 break 语句导致多个语言被执行的错误。
注意
虽然在 Swift 中 break 不是必须的,但你依然可以在 case 分支中的代码执行完毕前使用 break 跳出
区间匹配
case 分支的模式也可以是一个值的区间。下面的例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式:
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// 输出“There are dozens of moons orbiting Saturn.”
approximateCount 在一个 switch 声明中被评估。每一个 case 都与之进行比较。因为 approximateCount 落在了 12 到 100 的区间,所以 naturalCount 等于 “dozens of” 值,并且此后的执行跳出了 switch 语句。
复合型 Cases
当多个条件可以使用同一种方法来处理时,可以将这几种可能放在同一个 case 后面,并且用逗号隔开。当 case 后面的任意一种模式匹配的时候,这条分支就会被匹配。并且,如果匹配列表过长,还可以分行书写:
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) is not a vowel or a consonant")
}
// 输出“e is a vowel”
这个 switch 语句中的第一个 case,匹配了英语中的五个小写元音字母。相似的,第二个 case 匹配了英语中所有的小写辅音字母。最终,default 分支匹配了其它所有字符。