集合类型
本节内容包括:
Swift 语言里的数组和字典中存储的数据值类型必须明确。
注意: Swift 的数组结构在被声明成常量和变量或者被传入函数与方法中时会相对于其他类型展现出不同的特性。
<a name = "数组"></a>数组
Swift 数组特定于它所存储元素的类型。这与 Objective-C 的 NSArray 和 NSMutableArray 不同,这两个类可以存储任意类型的对象,并且不提供所返回对象的任何特别信息。在 Swift 中,数据值在被存储进入某个数组之前类型必须明确,方法是通过显式的类型标注或类型推断,而且不是必须是class类型。例如: 如果我们创建了一个Int值类型的数组,我们不能往其中插入任何不是Int类型的数据。 Swift 中的数组是类型安全的,并且它们中包含的类型必须明确。
数组的简单语法
写 Swift 数组应该遵循像Array<SomeType>这样的形式,其中SomeType是这个数组中唯一允许存在的数据类型。 我们也可以使用像[SomeType]这样的简单语法。
数组构造语句
可以使用字面量来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。
var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList 已经被构造并且拥有两个初始项。
//注意: Shoppinglist数组被声明为变量(var关键字创建)而不是
//常量(let创建)是因为以后可能会有更多的数据项被插入其中。
访问和修改数组
我们可以通过数组的方法和属性来访问和修改数组,或者下标语法。 还可以使用数组的只读属性count来获取数组中的数据项数量。
println("The shopping list contains \(shoppingList.count) items.")
// 输出"The shopping list contains 2 items."(这个数组有2个项)
使用布尔项isEmpty
来作为检查count
属性的值是否为 0 的捷径。
if shoppingList.isEmpty {
println("The shopping list is empty.")
} else {
println("The shopping list is not empty.")
}
// 打印 "The shopping list is not empty."(shoppinglist不是空的)
也可以使用append
方法在数组后面添加新的数据项:
shoppingList.append("Flour")
// shoppingList 现在有3个数据项,有人在摊煎饼
使用加法赋值运算符(+=)也可以直接在数组后面添加一个或多个拥有相同类型的数据项:
shoppingList += ["Baking Powder"]
// shoppingList 现在有四项了
shoppingList += ["Chocolate Spread","Cheese","Butter"]
// shoppingList 现在有七项了
数组的遍历
我们可以使用for-in
循环来遍历所有数组中的数据项:
for item in shoppingList {
println(item)
}
for (index, value) in enumerate(shoppingList) {
println("Item \(String(index + 1)): \(value)")
}
<a name = "集合"></a>集合
集合用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以把集合当做是数组另一形式。
Set类型语法
Swift中的Set类型被写为Set<SomeType>,这里的SomeType表示Set中允许存储的类型,和数组不同的是,集合没有等价的简化形式。
创建和构造一个Set
可以通过构造器语法创建一个特定类型的空集合:
var letters = Set<Character>()
集合与数组字面量
你可以使用一个数组字面量来构造一个集合,并且可以使用简化形式写一个或者多个值作为集合元素。
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
一个Set类型不能从数组中字面量中独立地被推断出来,因此Set类型必须显式声明。然而,由于Swift的类型推导功能,如果你想使用一个数组字面量构造一个Set并且该数组字面量中的所有元素类型相同,那么你无须写出Set的具体类型。
访问和修改一个Set
为了找出一个Set
中元素的数量,可以使用其只读属性count
:
println("I have \(favoriteGenres.count) favorite music genres.")
使用布尔属性isEmpty
作为一个缩写形式去检查count
属性是否为0:
if favoriteGenres.isEmpty {
println("As far as music goes, I'm not picky.")
} else {
println("I have particular music preferences.")
}
你可以通过调用Set
的insert(_:)
方法添加一个新的元素:
favoriteGenres.insert("Jazz")
你可以通过调用Set
的remove(_:)
方法去删除一个元素,如果该值是该Set
的一个元素则删除该元素并且返回被删除的元素值,否认如果该Set
不包含该值,则返回nil
。另外,Set
中的所有元素可以通过它的removeAll()
方法删除。
使用contains(_:)
方法去检查Set
中是否包含一个特定的值。
遍历一个Set
你可以在一个for-in
循环中遍历一个Set
中的所有值。
for genre in favoriteGenres {
println("\(value)")
}
Swift的Set类型没有确定的顺序,为了按照特定顺序来遍历一个Set中值可以使用全局sorted函数,它将根据提供的序列返回一个排序的集合.
for genre in sorted(favoriteGenres) {
println("\(genre)")
}
完成集合操作
- 使用
union(_:)
方法根据两个集合的值创建一个新的集合。 - 使用
subtract(_:)
方法根据不在该集合中的值创建一个新的集合。 - 使用
intersect(_:)
方法根据两个集合中都包含的值创建的一个新的集合。 - 使用
exclusiveOr(_:)
方法根据值在一个集合中但不在两个集合中的值创建一个新的集合。
Set类型的哈希值
为了存储在集合中,该类型必须是可哈希化的-也就是说,该类型必须提供一个方法来计算它的哈希值。一个哈希值是Int类型的,它和其他的对象相同,其被用来比较相等与否,比如a==b,它遵循的是a.hashValue == b.hashValue。
注意 你可以使用你自定义的类型作为集合的值或者是字典的键值类型,但你需要使你的自定义类型服从Swift标准库中的Hashable协议。服从Hashable协议的类型需要提供一个类型为Int的取值访问器属性hashValue。这个由类型的hashValue返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。 因为hashable协议服从于Equatable协议,所以遵循该协议的类型也必须提供一个"是否等"运算符(==)的实现。这个Equatable协议需要任何遵循的==的实现都是一种相等的关系。也就是说,对于a,b,c三个值来说,==的实现必须满足下面三种情况:
- a==a(自反性)
- a==b意味着b==a(对称性)
- a==b&&b==c意味着a==c(传递性)
<a name = "字典"></a>字典
字典是一种存储多个相同类型的值的容器。每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。
Swift 的字典使用时需要具体规定可以存储键和值类型。不同于 Objective-C 的NSDictionary和NSMutableDictionary 类可以使用任何类型的对象来作键和值并且不提供任何关于这些对象的本质信息。在 Swift 中,在某个特定字典中可以存储的键和值必须提前定义清楚,方法是通过显性类型标注或者类型推断。
Swift 的字典使用Dictionary<KeyType, ValueType>定义,其中KeyType是字典中键的数据类型,ValueType是字典中对应于这些键所存储值的数据类型。
字典字面量
var airports: [String:String] = ["TYO": "Tokyo", "DUB": "Dublin"]
读取和修改字典
我们可以通过字典的方法和属性来读取和修改字典,或者使用下标语法。和数组一样,我们可以通过字典的只读属性count
来获取某个字典的数据项数量:
println("The dictionary of airports contains \(airports.count) items.")
可以在字典中使用下标语法来添加新的数据项
airports["LHR"] = "London"
也可以使用下标语法来改变特定键对应的值:
airports["LHR"] = "London Heathrow"
字典的updateValue(forKey:)方法可以设置或者更新特定键对应的值。
字典遍历
我们可以使用for-in循环来遍历某个字典中的键值对。每一个字典中的数据项都由(key, value)元组形式返回,并且我们可以使用临时常量或者变量来分解这些元组:
for (airportCode, airportName) in airports {
println("\(airportCode): \(airportName)")
}
<a name = "集合的可变性"></a>集合的可变性
数组和字典都是在单个集合中存储可变值。如果我们创建一个数组或者字典并且把它分配成一个变量,这个集合将会是可变的。这意味着我们可以在创建之后添加更多或移除已存在的数据项来改变这个集合的大小。与此相反,如果我们把数组或字典分配成常量,那么它就是不可变的,它的大小不能被改变。