Swift Tour Learn (三) -- Swift 语法

2017-06-19  本文已影响97人  寒桥

本章将会介绍

数组类型(Arrays)
集合类型(Sets)
字典(Dictionaries)
控制流

数组类型(Arrays)

Swift 语言提供Arrays、Sets和Dictionaries三种基本的集合类型用来存储集合数据。数组(Arrays)是有序数据的集。集合(Sets)是无序无重复数据的集。字典(Dictionaries)是无序的键值对的集。


图片地址图片地址

Swift 语言中的Arrays、Sets和Dictionaries中存储的数据值类型必须明确。这意味着我们不能把不正确的数据类型插入其中。同时这也说明我们完全可以对取回值的类型非常自信。

注意:
Swift 的Arrays、Sets和Dictionaries类型被实现为泛型集合。更多关于泛型类型和集合

1.集合的可变性

如果创建一个Arrays、Sets或Dictionaries并且把它分配成一个变量,这个集合将会是可变的。这意味着我们可以在创建之后添加更多或移除已存在的数据项,或者改变集合中的数据项。如果我们把Arrays、Sets或Dictionaries分配成常量,那么它就是不可变的,它的大小和内容都不能被改变。

注意:
在我们不需要改变集合的时候创建不可变集合是很好的实践。如此 Swift 编译器可以优化我们创建的集合。

2.数组(Arrays)

数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。Swift 的Array类型被桥接到Foundation中的NSArray类。

var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// 打印 "someInts is of type [Int] with 0 items."

注意,通过构造函数的类型,someInts的值类型被推断为[Int]。
或者,如果代码上下文中已经提供了类型信息,例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:[](一对空方括号):

someInts.append(3)
// someInts 现在包含一个 Int 值
someInts = []
// someInts 现在是空数组,但是仍然是 [Int] 类型的。
var threeDoubles = Array(repeatElement(0.0, count: 3))
// threeDoubles 是一种 [Double] 数组,等价于 [0.0, 0.0, 0.0]
var someInts = [Int]()
someInts.append(3)

var streeDoubles = Array(repeatElement(4, count: 3))
var six = someInts + streeDoubles
// [3, 4, 4, 4]
var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList 已经被构造并且拥有两个初始项。

shoppingList变量被声明为“字符串值类型的数组“,记作[String]。 因为这个数组被规定只有String一种数据结构,所以只有String类型可以在其中被存取。 在这里,shoppingList数组由两个String值("Eggs" 和"Milk")构造,并且由数组字面量定义。

在这个例子中,字面量仅仅包含两个String值。匹配了该数组的变量声明(只能包含String的数组),所以这个字面量的分配过程可以作为用两个初始项来构造shoppingList的一种方式。

由于 Swift 的类型推断机制,当我们用字面量构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。 shoppingList的构造也可以这样写:

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

因为所有数组字面量中的值都是相同的类型,Swift 可以推断出[String]是shoppingList中变量的正确类型。

print("The shopping list contains \(shoppingList.count) items.")
// 输出 "The shopping list contains 2 items."(这个数组有2个项)
if shoppingList.isEmpty {
    print("The shopping list is empty.")
} else {
    print("The shopping list is not empty.")
}
// 打印 "The shopping list is not empty."(shoppinglist 不是空的)
shoppingList.append("Flour")
// shoppingList 现在有3个数据项,
shoppingList += ["Baking Powder"]
// shoppingList 现在有四项了
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList 现在有七项了
var firstItem = shoppingList[0]
// 第一项是 "Eggs"
shoppingList[0] = "Six eggs"
// 其中的第一项现在是 "Six eggs" 而不是 "Eggs"
shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList 现在有6项
shoppingList.insert("Maple Syrup", at: 0)
// shoppingList 现在有7项
// "Maple Syrup" 现在是这个列表中的第一项

这次insert(_:at:)方法调用把值为"Maple Syrup"的新数据项插入列表的最开始位置,并且使用0作为索引值。

let mapleSyrup = shoppingList.remove(at: 0)
// 索引值为0的数据项被移除
// shoppingList 现在只有6项,而且不包括 Maple Syrup
// mapleSyrup 常量的值等于被移除数据项的值 "Maple Syrup"
let apples = shoppingList.removeLast()
// 数组的最后一项被移除了
// shoppingList 现在只有5项,不包括 Apples
// apples 常量的值现在等于 "Apples" 字符串
3.数组的遍历
for item in shoppingList {
    print(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas
for (index, value) in shoppingList. enumerated() {
    print("Item \(String(index + 1)): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas
4.数组总结
// 数组

// 创建一个空数组
var someInts = [Int]()
// 通过构造函数的类型,someInt的值的类型被推断为[Int]

// 为数组添加元素
someInts.append(3)

// 数组制空
someInts = []
// 使用repeat方法添加元素
someInts = Array(repeatElement(3, count: 2))

// 两个数组相加
var anotherIntArray = Array(repeatElement(2, count: 3))
// 注意必须保证两个合并的数组元素类型一致
var totalAyyay = someInts + anotherIntArray

// 字面量创建数组
var shoppingList = ["Eggs", "Milk"]
// 根据类型推断创建的是[String]类型的数组 隐式类型

// 获取数组元素
shoppingList.count

// 判断数组个数是否为0
shoppingList.isEmpty

// 使用append方法添加元素
shoppingList.append("Flour")

// 使用加法赋值运算符 += 直接在数组后边添加一个或多个相同类型的元素
shoppingList += ["Baking Powder"]
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]

// 使用索引获取数组元素
shoppingList[0]

// 根据下表索引修改元素
shoppingList[0] = "Six Eggs"
shoppingList

// 利用下标区间修改多个元素
shoppingList[4...6] = ["Bananas", "Apples"]
shoppingList

// 调用insert方法在某个位置插入元素
shoppingList.insert("Maple Syrup", at: 0)

// 调用remove方法移除数组中的某一项
shoppingList.remove(at: 0)
shoppingList

// 移除最后一项
shoppingList.removeLast()
shoppingList

// 移除第一项
shoppingList.removeFirst()
shoppingList

// 数组的遍历
for item in shoppingList {
   print(item)
}

// 遍历数组元素和索引
for (index, value) in shoppingList.enumerated() {
    print("Item \(String(index + 1)): \(value)")
}


集合类型(Sets)

集合(Set)用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。

Swift的Set类型被桥接到Foundation中的NSSet类。

1.集合类型的哈希值

一个类型为了存储在集合中,该类型必须是可哈希化的--也就是说,该类型必须提供一个方法来计算它的哈希值。一个哈希值是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(传递性)

2.集合类型的语法

Swift 中的Set类型被写为Set<Element>,这里的Element表示Set中允许存储的类型,和数组不同的是,集合没有等价的简化形式。

var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
// 打印 "letters is of type Set<Character> with 0 items."

通过构造器,这里的letters变量的类型被推断为Set<Character>。

此外,如果上下文提供了类型信息,比如作为函数的参数或者已知类型的变量或常量,我们可以通过一个空的数组字面量创建一个空的Set:

letters.insert("a")
// letters 现在含有1个 Character 类型的值
letters = []
// letters 现在是一个空的 Set, 但是它依然是 Set<Character> 类型
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres 被构造成含有三个初始值的集合

这个favoriteGenres变量被声明为“一个String值的集合”,写为Set<String>。由于这个特定的集合含有指定String类型的值,所以它只允许存储String类型值。这里的favoriteGenres变量有三个String类型的初始值("Rock","Classical"和"Hip hop"),并以数组字面量的方式出现。

var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]

由于数组字面量中的所有元素类型相同,Swift 可以推断出Set<String>作为favoriteGenres变量的正确类型。

3.访问和修改一个集合
print("I have \(favoriteGenres.count) favorite music genres.")
// 打印 "I have 3 favorite music genres."
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."
favoriteGenres.insert("Jazz")
// favoriteGenres 现在包含4个元素
if let removedGenre = favoriteGenres.remove("Rock") {
    print("\(removedGenre)? I'm over it.")
} else {
    print("I never much cared for that.")
}
// 打印 "Rock? I'm over it."
if favoriteGenres.contains("Funk") {
    print("I get up on the good foot.")
} else {
    print("It's too funky in here.")
}
// 打印 "It's too funky in here."
4.遍历一个集合
for genre in favoriteGenres {
    print("\(genre)")
}
// Classical
// Jazz
// Hip hop
for genre in favoriteGenres.sorted() {
    print("\(genre)")
}
// prints "Classical"
// prints "Hip hop"
// prints "Jazz
5.集合操作

你可以高效地完成Set的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。

let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]

oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits. intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits. symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]

houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true
6.集合总结
// 集合

// 创建和构造一个空集合
var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")

// 给集合添加元素
letters.insert("a")
letters

// 清空集合
letters = []
letters

// 用数组字面量创建集合
var favoriteGenres: Set = ["Rock", "Classical", "Hip Hop"]
// 根据类型推断 知道favoriteGenres是Set<String>类型的

// 读取集合中元素个数
favoriteGenres.count
// 判断集合中元素个数是否是0
favoriteGenres.isEmpty

// 通过insert方法添加元素
favoriteGenres.insert("Jazz")
favoriteGenres

// 通过remove方法删除集合中一个元素
favoriteGenres.remove("Rock")
favoriteGenres

// 使用contains检查集合中是否包含特定的值
favoriteGenres.contains("Jazz")

// 遍历集合
for genre in favoriteGenres {
    print(genre)
}

// 按照特定顺序遍历集合 默认按照“<”操作符进行遍历
for genre in favoriteGenres.sorted() {
    print(genre)
}

let oddDigits: Set = [1,3,5,7,9]
let evenDigits: Set = [0,2,4,6,8]
let singleDigitPrimeNumbers: Set = [2,3,5,7]
// 两个集合的交集
oddDigits.intersection(evenDigits).sorted()
// 两个集合的并集
oddDigits.union(evenDigits).sorted()
// 在一个集合中但不在两个集合中的值创建一个新的集合
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()

字典(Dictionaries)

字典是一种存储多个相同类型的值的容器。每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。和数组中的数据项不同,字典中的数据项并没有具体顺序。我们在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。

Swift 的Dictionary类型被桥接到Foundation的NSDictionary类。

1.字典类型简化语法

Swift 的字典使用Dictionary<Key, Value>定义,其中Key是字典中键的数据类型,Value是字典中对应于这些键所存储值的数据类型。

注意:
一个字典的Key类型必须遵循Hashable协议,就像Set的值类型。
我们也可以用[Key: Value]这样简化的形式去创建一个字典类型。虽然这两种形式功能上相同,但是后者是首选。

2.字典
var namesOfIntegers = [Int: String]()
// namesOfIntegers 是一个空的 [Int: String] 字典

这个例子创建了一个[Int: String]类型的空字典来储存整数的英语命名。它的键是Int型,值是String型。

namesOfIntegers[16] = "sixteen"
// namesOfIntegers 现在包含一个键值对
namesOfIntegers = [:]
// namesOfIntegers 又成为了一个 [Int: String] 类型的空字典
[key 1: value 1, key 2: value 2, key 3: value 3]
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

airports字典被声明为一种[String: String]类型,这意味着这个字典的键和值都是String类型。

airports字典使用字典字面量初始化,包含两个键值对。第一对的键是YYZ,值是Toronto Pearson。第二对的键是DUB,值是Dublin。

这个字典语句包含了两个String: String类型的键值对。它们对应airports变量声明的类型(一个只有String键和String值的字典)所以这个字典字面量的任务是构造拥有两个初始数据项的airport字典。

var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

因为这个语句中所有的键和值都各自拥有相同的数据类型,Swift 可以推断出Dictionary<String, String>是airports字典的正确类型。

2.访问和修改字典

我们可以通过字典的方法和属性来访问和修改字典,或者通过使用下标语法。

print("The dictionary of airports contains \(airports.count) items.")
// 打印 "The dictionary of airports contains 2 items."(这个字典有两个数据项)
if airports.isEmpty {
    print("The airports dictionary is empty.")
} else {
    print("The airports dictionary is not empty.")
}
// 打印 "The airports dictionary is not empty."
airports["LHR"] = "London"
// airports 字典现在有三个数据项
airports["LHR"] = "London Heathrow"
// "LHR"对应的值 被改为 "London Heathrow
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
    print("The old value for DUB was \(oldValue).")
}
// 输出 "The old value for DUB was Dublin."
if let airportName = airports["DUB"] {
    print("The name of the airport is \(airportName).")
} else {
    print("That airport is not in the airports dictionary.")
}
// 打印 "The name of the airport is Dublin Airport."
airports["APL"] = "Apple Internation"
// "Apple Internation" 不是真的 APL 机场, 删除它
airports["APL"] = nil
// APL 现在被移除了
if let removedValue = airports. removeValue(forKey: "DUB") {
    print("The removed airport's name is \(removedValue).")
} else {
    print("The airports dictionary does not contain a value for DUB.")
}
// prints "The removed airport's name is Dublin Airport."
3.字典遍历
for (airportCode, airportName) in airports {
    print("\(airportCode): \(airportName)")
}
// YYZ: Toronto Pearson
// LHR: London Heathrow
for airportCode in airports.keys {
    print("Airport code: \(airportCode)")
}
// Airport code: YYZ
// Airport code: LHR

for airportName in airports.values {
    print("Airport name: \(airportName)")
}
// Airport name: Toronto Pearson
// Airport name: London Heathrow
let airportCodes = [String](airports.keys)
// airportCodes 是 ["YYZ", "LHR"]

let airportNames = [String](airports.values)
// airportNames 是 ["Toronto Pearson", "London Heathrow"]

Swift 的字典类型是无序集合类型。为了以特定的顺序遍历字典的键或值,可以对字典的keys或values属性使用sorted()方法。

3.字典总结
// 字典

// 创建一个空字典
var nameOfIntegers = [Int: String]()

// 添加元素
nameOfIntegers[16] = "sixteen"
nameOfIntegers

// 清空字典
nameOfIntegers = [:]

// 用字典字面量创建字典
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// 根据类型推断 airports的类型是[String: String]

// 字典元素个数
airports.count

// 判断字典元素个数是否是0
airports.isEmpty

// 使用下标语法添加新的元素
airports["LHR"] = "London"
airports

// 使用下标语法来更改元素
airports["LHR"] = "London Heathrow"
airports

// updateValue(_:forKey:)方法可以设置或者更新特定键对应的值,返回之前的值
airports.updateValue("Dubin Airport", forKey: "DUB")
airports

// 将某个键值设置成nil,删除某个元素
airports["DUB"] = nil
airports

// 根据键删除某个元素
airports.removeValue(forKey: "LHR")
airports

airports["APL"] = "Apple Internation"
airports["LHR"] = "London Heathrow"
airports

// 字典遍历
for (airportCode, airportName) in airports {
    print("\(airportCode) : \(airportName)")
}

// 遍历所有的keys
for airportCode in airports.keys.sorted() {
    print(airportCode)
}

// 遍历所有的values
for airportName in airports.values {
    print(airportName)
}
上一篇 下一篇

猜你喜欢

热点阅读