Swift中文教程(四) 集合类型

时间:2022-02-01 20:47:43

Swift中文教程(四) 集合类型

Swift 提供两种集合类型来存储集合,数组和字典。数组是一个同类型的序列化列表集合。字典是一个能够使用类似于键的唯一标识符来获取值的非序列化集合。

在Swift中,数组和字典的键和值都必须明确它的类型。这意味这数组和字典不会插入一个错误的类型的值,以致于出错。这也意味着当你在数组和字典中取回数值的时候能够确定它的类型。
Swift 使用确定的集合类型可以保证代码工作是不会出错,和让你在开发阶段就能更早的捕获错误。
note
Swift的数组 储存不同的类型会展示出不同的行为,例如变量,常量或者 函数和方法。更多的信息参见Mutability of Collections and Assignment 和 Copy Behavior for Collection Types.

1、数组
数组是储存同类型不同值的序列化列表。同样的值可以在数组的不同位置出现多次。

Swift数组是储存确定的值,这个Objective-C中的NSArray和NSMutableArray类是有区别的。因为它们是储存各种的对象,而且并不提供返回任何有关对象的具体信息。在Swift中,无论是确定的声明,还是隐式的声明,数组是非常确定它自身是储存什么样的类型,而且,它并不一定要求储存的是类对象。所以Swift数组是类型安全的,因为它一直都确定它自身所能包含的值。

数组的简略语法
定义数组的完整写法是Array<SomeType>。其中SomeType是你想要包含的类型。你也可以使用类似于SomeType[]这样的简略语法。虽然这两种方法在功能上是相同的。但是我们更推荐后者,而且它会一直贯穿于本书。

数组实量(Array Literals)
你可以用一个数组实量(Array Literals)来初始化一个数组,它是用简略写法来创建一个包含一个或多个的值的数组。一个数组实量(Array Literals)是由它包含的值,“,”分隔符 已经包括以上内容的中括号对“[]”组成:

[value 1, value 2, value 3]

下面的例子创建一个叫shoppinglist,储存字符串(String)类型的数组。

var shoppingList: String[] = ["Eggs", "Milk"] // 使用两个初始化参数来初始化shoppingList

shoppinglist变量被定义为字符串(String)类型的数组,写作String[]。因为这个数组被确定为字符串类型(String),所以它只能储存字符串(String)类型的值。在这里,用两个字符串类型的值(”Eggs” and “Milk”)和数组实量(Array Literals)的写法来初始化shoppingList数组。

注意
shoppingList数组是被定义为一个变量(使用var 标识符)而不是常量(使用let 标识符),所以在下面的例子可以直接添加元素。

在这个例子中,数组实量(Array Literals)只包含两个字符串类型的值,这符合了shoppingList变量的定义(只能包含字符串(String)类型的数组),所以被分配的数组实量(Array Literals)被允许用两个字符串类型的值来初始化。

得益于Swift的类型推断,当你用相同类型的值来初始化时,你可以不写明类型。初始化shoppingList可以用下面这个方法来代替。

var shoppingList = ["Eggs", “Milk"]

因为数组实量(Array Literals)中所有的值都是同类型的,所以Swift能够推断shoppingList的类型为字符串数组(String[])。

读取和修改数组
你可以通过方法和属性,或者下标来读取和修改数组。

通过只读属性count来读取数组的长度;

println("The shopping list contains \(shoppingList.count) items.") 
// prints "The shopping list contains 2 items.”

通过一个返回布尔类型的isEmpty属性检查数组的长度是否为0

if shoppingList.isEmpty 
{     
println("The shopping list is empty.") 
} 
else {     
println("The shopping list is not empty.") 
} // prints "The shopping list is not empty."

在数组末尾增加一个元素可以通过append方法

shoppingList.append("Flour") // shoppingList 现在包含3个元素

甚至,还可以用(+=)操作符来把一个元素添加到数组末尾

shoppingList += "Baking Powder" // shoppingList 现在包含4个元素

你也可以用(+=)操作符来把一个数组添加到另一个数组的末尾

shoppingList += ["Chocolate Spread", "Cheese", "Butter"] // shoppingList 现在包含7个元素

从数组中取出一个值可以使用下标语法。如果你知道一个元素的索引值,你可以数组名后面的中括号中填写索引值来获取这个元素

var firstItem = shoppingList[0] // firstItem 等于 “Eggs"

注意,数组的第一个元素的索引值为0,不为1,Swift的数组总是索引0;

你可以使用下标语法通过索引修改已经存在的值。

shoppingList[0] = "Six eggs" //列表中的第一个值等于"Six eggs" 而不等于 “Eggs"

你可以使用下标语法一次性改变一系列的值,尽管修改的区域远远大于要修改的值。在下面的雷子中, 替换掉 “Chocolate Spread”, “Cheese”,”Butter”,”Bananas”,”Apples”:

shoppingList[4...6] = ["Bananas", "Apples"] // shoppingList 现在包含6个元素

注意,你不能使用下标语法在数组中添加一个元素,如果你尝试使用下标语法来获取或者设置一个元素,你将得到一个运行时的错误。尽管如此,你可以通过count属性验证索引是否正确再使用它。当count为0时(意味着数组为空),则count-1超出了索引的有效范围,因为数组的索引总是从0开始。

在一个特定的索引位置插入一个值,可以使用insert(atIndex:)方法

shoppingList.insert("Maple Syrup", atIndex: 0) 
// shoppingList 现在包含7个元素 
// "Maple Syrup" 在数组的第一位

这里调用insert方法指明在shoppingList的索引为0的位置中插入一个新元素 “Maple Syrup”

同理,你可以调用removeAtIndex方法移除特定的元素。这个方法移除特定索引位置的元素,已经返回这个被移除的元素(尽管你并不关心这个返回值)。

let mapleSyrup = shoppingList.removeAtIndex(0) 
// 索引位置为0的元素被移除  
// shoppingList 现在包含6个元素, 不包括 Maple Syrup 
// mapleSyrup 常量等于被移除的 "Maple Syrup" 字符串

当元素被移除的,数组空缺的位置将会被填补,所以现在索引位置为0的元素再一次等于”Six eggs”:

firstItem = shoppingList[0] // firstItem 现在等于 "Six eggs”

如果你从数组中移除最后一个元素,使用removeLast方法比removeAtIndex更方便,因为后者需要通过count属性计算数组的长度。和removeAtIndex方法一样,removeLast会返回被移除的元素。

let apples = shoppingList.removeLast() 
//元素的最后一个元素被移除 
// shoppingList 现在包含5个元素,不包括 cheese
// apples 常量 现在等于被移除的 "Apples" string

遍历数组
可以使用for-in循环来遍历数组中的值

for item in shoppingList {     println(item) } 
// Six eggs 
// Milk 
// Flour 
// Baking Powder 
// Bananas

如果需要每一个元素的整形的索引值,使用enumerate函数代替会更方便,enumerate函数对于每一个元素都会返回一个包含元素的索引和值的元组(tuple)。你可以在遍历部分分解元祖并储存在临时变量或者常量中。

for (index, value) in enumerate(shoppingList) 
{     
println("Item \(index + 1): \(value)") 
} 
// 元素 1: Six eggs 
// 元素 2: Milk 
// 元素 3: Flour 
// 元素 4: Baking Powder 
// 元素 5: Bananas

如需更多for-in 循环信息, 参见 For Loops.

创建和初始化数组
创建一个空的数组和确定的类型(不包含初始化值)使用的初始化语法

var someInts = Int[]()
 println("someInts is of type Int[] with \(someInts.count) items.") 
// prints "someInts is of type Int[] with 0 items.”

注意,someInt变量被确定为Int[],因为它使用生成Int[]的初始化方法。

或者,如果上下文(context)已经提供类型信息,例如函数参数或者已经确定类型的常量和变量,你可以从空的数组实量(Array Literals)创建一个空数组,写作[](空的中括号对)。

someInts.append(3) 
// someInts 现在包含1个Int型的元素 
someInts = [] 
// someInts 现在是一个空的数组, 但是类型仍然为Int[];

Swift数组类型也提供初始化方法来创建确定长度和提供默认数值的数组。你可以通过这个初始化方法增加一个新的数组,元素的数量成为count,合适的默认值为repeatedValue

var threeDoubles = Double[](count: 3, repeatedValue: 0.0) 
// threeDoubles 的类型为 Double[], 以及等于 [0.0, 0.0, 0.0]

得益于类型推断,你并不需要指明这个数组储存的类型就能使用这个初始化方法,因为它从默认值中就能推断出来。

var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5) 
// anotherThreeDoubles 被推断为 Double[], 以及等于 [2.5, 2.5, 2.5]

最后,你可以使用(+)操作符就能创建一个新的数组,把两个存在的数组添加进来
这个新的数组类型从你添加的两个数组中推断出来

var sixDoubles = threeDoubles + anotherThreeDoubles // sixDoubles 被推断为 Double[], 并等于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]