Swift 数组
了解 Swift 数组,以及如何创建、初始化、管理并操作数组。
数组和字典是 Swift 中用于存储其他对象集合的容器。在本课中,我们将介绍使用 Swift 数组和字典的一些基础知识。
可变与不可变集合
Swift 中的集合分为可变和不可变两种形式。不可变集合在初始化后其内容无法更改。要创建一个不可变集合,使用 let 关键字将其赋值给常量。相反,如果将集合赋值给变量(使用 var),则该集合是可变的。
Swift 数组初始化
数组是一种专门设计用来在一个有序集合中存储多个值的数据类型。例如,可以创建一个用于存储字符串值列表的数组。严格来说,一个 Swift 数组只能存储相同类型的值。因此,声明为存储字符串的数组不能同时包含整数。不过,也可以创建混合类型的数组,这将在本章稍后展示。数组的类型可以通过类型标注指定,也可以由编译器通过类型推断自动识别。
可以在创建时通过一组值(称为数组字面量)来初始化数组,语法如下:
1var 变量名: [类型] = [值1, 值2, 值3, ……]
以下代码创建了一个赋值给变量的新数组(因此是可变的),并用三个字符串值进行初始化:
1var treeArray = ["Pine", "Oak", "Yew"]
或者,同样的数组也可以通过赋值给常量来创建为不可变的:
1let treeArray = ["Pine", "Oak", "Yew"]
在上述情况下,Swift 编译器会使用类型推断确定数组包含的是 String 类型的值,并防止其他类型值被插入到应用程序的其他位置。
也可以使用类型标注来声明相同的数组:
1var treeArray: [String] = ["Pine", "Oak", "Yew"]
数组在创建时不必立即赋值。以下语法可用于创建一个空数组:
1var 变量名 = [类型]()
例如,以下代码创建了一个用于存储浮点数值的空数组,并将其赋值给名为 priceArray 的变量:
1var priceArray = [Float]()
另一种有用的初始化技术允许数组以指定大小创建,并且每个元素都预先设置为某个默认值:
1var nameArray = [String](repeating: "My String", count: 10)
当编译并执行时,上述代码将创建一个包含 10 个元素的新数组,每个元素初始值均为“My String”。
最后,可以通过将两个现有数组相加(前提是两个数组的元素类型相同)来创建一个新数组。例如:
1let firstArray = ["Red", "Green", "Blue"] 2let secondArray = ["Indigo", "Violet"] 3 4let thirdArray = firstArray + secondArray
在 Swift 中操作数组
一旦数组存在,就可以使用 Swift 提供的大量方法和属性来操作和处理数组内容。以下是部分常用功能:
获取数组元素数量
通过访问数组的 count 属性可以获得数组中项目的数量:
1var treeArray = ["Pine", "Oak", "Yew"] 2var itemCount = treeArray.count 3 4print("项目数量 = \(itemCount)")
判断数组是否为空,可以使用数组的布尔属性 isEmpty:
1var treeArray = [String]() 2 3if treeArray.isEmpty { 4 print("数组为空。") 5} else { 6 print("项目数量 = \(treeArray.count)") 7}
访问数组元素
可以通过索引下标(第一个元素的索引为 0)来访问或修改数组中的特定元素,这种方法称为索引下标访问。以下代码片段输出了数组中索引位置 2 处的字符串值(即 “Yew”):
1var treeArray = ["Pine", "Oak", "Yew"] 2 3print(treeArray[2])
此方法也可用于替换指定索引位置的值:
1var treeArray = ["Pine", "Oak", "Yew"] 2 3print("第1项 = \(treeArray[1])") 4treeArray[1] = "Redwood" 5print("第1项 = \(treeArray[1])")
上述代码将索引位置 1 的当前值替换为 “Redwood”。
遍历数组
遍历数组中最简单的方法是使用 for-in 循环语法。例如,以下代码遍历一个字符串数组的所有元素,并将每个元素输出到控制台:
1let treeArray = ["Pine", "Oak", "Yew", "Maple", "Birch", "Myrtle"] 2 3for tree in treeArray { 4 print(tree) 5}
相同的效果也可以通过调用数组的 forEach() 方法实现。当对数组调用此方法时,它会遍历每个元素并执行指定的代码。例如:
1let treeArray = ["Pine", "Oak", "Yew", "Maple", "Birch", "Myrtle"] 2 3treeArray.forEach { tree in 4 print(tree) 5}
注意,由于每个元素需要执行的任务是以闭包表达式形式定义的,因此可以利用简写参数名进行优化:
1treeArray.forEach { 2 print($0) 3}
随机元素与打乱顺序
调用数组对象的 shuffled() 方法将返回一个随机重新排列顺序的新数组。例如:
1let shuffledTrees = treeArray.shuffled()
要随机访问数组中的一个元素,只需调用 randomElement() 方法:
1let treeArray: [String] = ["Pine", "Oak", "Yew", "Maple", "Birch", "Myrtle"] 2 3print("随机元素 = \(treeArray.randomElement()!)") 4print("随机元素 = \(treeArray.randomElement()!)") 5print("随机元素 = \(treeArray.randomElement()!)")
向数组添加元素
可以使用 append 方法或 + 和 += 运算符向数组添加元素。例如,以下都是向数组添加元素的有效方式:
1var treeArray = ["Pine", "Oak", "Yew"] 2 3treeArray.append("Redwood") 4treeArray += ["Myrtle"] 5treeArray += ["Elm", "Maple", "Birch"] 6 7for tree in treeArray { 8 print(tree) 9}
插入和删除数组元素
可以通过调用数组的 insert(at:) 方法,在指定索引位置插入新元素。插入操作会保留原有所有元素,相当于将它们向右移动以腾出空间:
1var treeArray = ["Pine", "Oak", "Yew"] 2 3treeArray.insert("Maple", at: 0) 4 5for tree in treeArray { 6 print(tree) 7}
类似地,可以通过调用 remove(at:) 方法删除指定索引位置的元素:
1var treeArray = ["Pine", "Oak", "Yew"] 2 3treeArray.remove(at: 2) 4 5for tree in treeArray { 6 print(tree) 7}
要删除数组的最后一个元素,只需调用数组的 removeLast() 方法:
1var treeArray = ["Pine", "Oak", "Yew"] 2 3treeArray.removeLast() 4 5for tree in treeArray { 6 print(tree) 7}
创建混合类型数组
混合类型数组是指可以包含不同类型元素的数组。显然,如果一个数组被声明或推断为 String 类型,则不能再用于存储非字符串类型的对象实例。然而,考虑到 Swift 提供了 Any 类型,情况变得有趣起来。Any 是 Swift 中一种特殊类型,可用于引用任意非特定类类型的对象。因此,声明为包含 Any 类型元素的数组可以存储多种类型的元素。例如,以下代码声明并初始化了一个包含字符串、整数和双精度浮点数元素的混合数组:
1let mixedArray: [Any] = ["A String", 432, 34.989]
使用 Any 类型需谨慎,因为 Any 会隐藏元素的真实类型,使代码容易出现程序员错误。通常需要手动将 Any 数组中的元素转换为正确的类型才能使用。如果对某个元素进行了错误的类型转换,代码可能在编译时不会报错,但在运行时会崩溃。举个例子,考虑以下混合类型数组:
1let mixedArray: [Any] = [1, 2, 45, "Hello"]
假设我们想遍历数组中的整数元素并将它们乘以 10。实现代码可能是这样的:
1let mixedArray: [Any] = ["A String", 432, 34.989] 2 3for object in mixedArray { 4 print(object * 10) 5}
但编译时会触发语法错误,提示无法对 Any 和 Int 类型的操作数进行乘法运算。
1error: cannot convert value of type 'Any' to expected argument type 'Int'
为消除此错误,必须将数组元素向下转型为 Int 类型:
1let mixedArray: [Any] = ["A String", 432, 34.989] 2 3for object in mixedArray { 4 print(object as! Int * 10) 5}
上述代码可以成功编译,但在遇到第一个非整数元素时将导致程序崩溃,报错如下:
1Could not cast value of type 'Swift.String' (0x7fbc071fca58) to 'Swift.Int' (0x7fbc071fe688).
因此,代码必须修改为能够识别每个元素的具体类型。显然,使用 Any 数组在 Swift 中既有优势也有风险。
课程总结
-
数组在一个有序集合中存储多个值。
-
赋值给常量的数组是不可变的。
-
赋值给变量的数组是可变的。
-
数组可以声明为空,也可以用一组已有元素(称为数组字面量)进行预初始化。
-
可使用一系列属性和方法获取数组信息,并进行访问、添加、打乱和删除元素。
-
通过将元素类型设为
Any可以声明混合类型数组。这是一种应谨慎使用的技巧。
测验
通过测验检验你对 Swift 数组的理解。
练习
通过以下练习巩固你对 Swift 数组的掌握。
练习 1
编写代码,遍历并显示以下数组中的每个元素:
练习
1let myArray = [1, 4, 6, 12, 5, 3, 6]
解答
1let myArray = [1, 4, 6, 12, 5, 3, 6] 2 3for item in myArray { 4 print(item) 5}
练习 2
添加代码,删除以下数组的最后一个元素:
练习
1var myArray = ["Kia", "Ford", "Audi", "Toyota", "BMW", "Tesla"] 2 3for item in myArray { 4 print(item) 5}
解答
1var myArray = ["Kia", "Ford", "Audi", "Toyota", "BMW", "Tesla"] 2 3myArray.removeLast() 4 5for item in myArray { 6 print(item) 7}
练习 3
创建一个包含 20 个元素的数组,每个元素都为数字 10。
练习
1let myArray =
解答
1let myArray = [Int](repeating: 10, count: 20) 2 3for item in myArray { 4 print(item) 5}
Quiz
给定语句 colorArray[2] 可访问数组中包含字符串 "Red" 的元素,以下哪个语句将该元素赋值给常量 redColor?