可選型
可選型是 Swift
語言中的一種類型宦芦,其寫法為基本數(shù)據(jù)類型后加一個問號雨让,表示某個變量可能是 nil
。
- 聲明
其聲明如下所示:
var number:Int? = nil //整型的可選型 (可選型可以初始化為 nil)
var errorCode:String? = "404" //字符串的可選型 (String? 類型)
var errorMessage:String? = "Not found"
print(errorCode) //打印結(jié)果為 Optional("404")
可選型不能直接使用丽涩,需要進(jìn)行解包:
"The errorCode is " + errorCode //error, 可選型不能直接使用
- 解包
解包桐腌,即獲取可選型變量的值拄显。
//強(qiáng)制解包 (可選型后加嘆號),保證該值不為 nil (該做法有風(fēng)險案站,若為 nil 則會報錯)
"The errorCode is " + errorCode!
//一般做法
if errorCode != nil {
"The errorCode is " + errorCode!
}
//Swift 新的語法 (if...let 解包)
if let errorCode = errorCode {
"The errorCode is " + errorCode //二者可同名躬审,前者是 String 類型,后者為 String? 類型
}
//多個可選型變量同時解包蟆盐,示例代碼:
if let errorCode = errorCode,
errorMessage = errorMessage {
print("OK")
}
//此外盒件,還可增加邏輯判斷,例如添加 where:
if let errorCode = errorCode,
errorMessage = errorMessage where errorCode == "404" {
print("Not found")
}
- Optional Chaining
Optional Chaining: 自動判斷鏈
//對一個可選型解包后舱禽,并進(jìn)行一些操作
if let errorMessage = errorMessage {
errorMessage.uppercaseString
}
errorMessage?.uppercaseString //返回值類型為可選型。該寫法與前者等效
//errorMessage!.uppercaseString //若這樣寫 errorMessage 為 nil 時報錯
var uppercaseErrorMessage = errorMessage?.uppercaseString //uppercaseErrorMessage 是String? 類型
if let uppercaseErrorMessage = errorMessage?.uppercaseString {
uppercaseErrorMessage
}
- nil coalescing
var error:String? = nil
let message:String //這里的 massage 未賦值恩沽,不能使用
if let errorMessage = error {
message = errorMessage
}
else {
message = "no error"
}
//若使用三目運算符
let message2 = error == nil ? "no error" : error
//若使用 Swift 新語法(與前面二者等效誊稚。即優(yōu)先取 error 的值,若為 nil, 則為 ?? 后的值)
let message3 = error ?? "no error"
- 隱式可選型
基本類型后加感嘆號罗心,例如:
var errMessage:String! = nil //也是可選型里伯,不用解包
errMessage = "not found"
"the message is " + errMessage //為空的時候報錯
數(shù)組
- 聲明
var numbers = [1, 2, 3, 4, 5]
var strs = ["A", "E", "I", "O", "U"]
//顯式聲明
var numbers: [Int] = [1, 2, 3, 4, 5]
var strs:Array<String> = ["A", "E", "I", "O", "U"]
//聲明空數(shù)組(四種方式均可)
var emptyArr1:[Int] = []
var emptyArr2:Array<Int> = []
var emptyArr3 = [Int]()
var emptyArr4 = Array<Int>()
- 常用方法
numbers.count //數(shù)組長度
numbers.isEmpty //是否為空
numbers[4] //第幾個元素
numbers.first //第一個元素。注:返回值為可選型
numbers.last //最后一個元素渤闷。返回值為可選型
numbers.contains(1) //是否包含某個元素
numbers.minElement() //最小值
numbers.maxElement() //最大值
strs.minElement() //OK, 字符串型的數(shù)組也可以比較
strs.maxElement()
numbers[1..<3] //獲得子數(shù)組
numbers.indexOf(3) //某個元素的索引疾瓮,若沒有,則返回 nil
- 遍歷
//方式一
for index in 0..<numbers.count {
print(numbers[index])
}
//方式二
for index in numbers {
print(index)
}
//新的遍歷方式飒箭,可以同時獲得索引和值
for (i, value) in strs.enumerate() {
print("\(i): \(value)")
}
- 比較
兩個數(shù)組可以進(jìn)行比較狼电,例如:
var numbers = [1, 2, 3, 4, 5]
var oneToFive = [1, 2, 3, 4, 5]
numbers == oneToFive //true, 這里比較的是值蜒灰,而非引用
注意:若順序不同,則不相等肩碟。因為數(shù)組是有序的强窖!
- 增刪改
//向數(shù)組中添加元素
numbers.append("hello") //向數(shù)組中添加元素(到末尾)
numbers.append(8) //數(shù)組中添加元素(到末尾)
numbers += [7, 9] //數(shù)組連接,后者要為數(shù)組
numbers.insert(10, atIndex: 5) //插入到指定位置(注意越界問題)
//刪除元素
numbers2.removeLast() //移除最后一個元素
numbers2.removeFirst() //移除第一個元素
numbers2.removeAtIndex(3) //移除指定索引的元素
numbers2.removeRange(0..<2) //移除某個范圍內(nèi)的元素
numbers2.removeAll() //刪除全部
//修改元素
numbers[1] = 3 //修改某個元素
numbers[0...2] = [2, 2] //修改某個區(qū)間的元素(注意越界問題)
- 二維數(shù)組
//聲明
var arr = [[1, 1], [2, 3, 5], [8, 13, 21, 34]] //[Array<Int>] 類型
var arr:[[Int]] = [[1], [2, 3], [3, 4]] //顯示聲明
var arr:Array<Array<Int>> = [[1, 2], [2, 3], [3, 4]]
arr[0] //第一行
arr[0][0] //第一行的第一個元素
arr.count //數(shù)組的長度
arr[0].count //一行的個數(shù)
arr[0].append(0) //第一行添加一個元素
arr.append([1, 2, 3, 4]) //添加一行
arr += [[0, 0]] //二維數(shù)組添加一個元素
arr[0] += [0, 0] //第一行添加兩個元素
字典和集合
- 聲明
var dict = ["hi":1, "hello":2]
//顯示聲明
var dict:[String : String] = ["swift":"雨燕削祈;迅速的", "python":"大蟒"]
var dict:Dictionary<String, String> = ["swift":"雨燕翅溺;迅速的", "python":"大蟒"]
//聲明空的字典
var emptyDict1:[String:Int] = [:]
var emptyDict2:Dictionary<String, Int> = [:]
var emptyDict3 = [String:String]()
var emptyDict4 = Dictionary<String, String>()
- 解包
dict["swift"] //獲取 swift 對應(yīng)的值,返回可選型髓抑,因為可能不存在
if let value = dict["swift"] {
print(value)
}
- 常用方法
dict.count //多少鍵值對
dict.isEmpty //是否為空
Array(dict.keys) //獲取所有的 key
Array(dict.values) //獲取所有的 value
- 遍歷
//遍歷 key
for key in dict.keys {
print(key) //注意:字典是無序的數(shù)據(jù)集合s
}
//遍歷獲取 key, value
for (key, value) in dict {
print("\(key) : \(value)")
}
- 比較
let dict1 = [1:"a", 2:"b", 3:"c"]
let dict2 = [3:"c", 1:"a", 2:"b"]
dict1 == dict2 //true, 比較的是值咙崎,和順序無關(guān),但鍵不能重復(fù)
- 刪改
var dict = ["name":"Luffy", "occupation":"pirate"]
//修改
dict["name"] = "Zoro" //注意:若 key 存在吨拍,則修改褪猛;若不存在,則增加進(jìn)去
dict.updateValue("swordsman", forKey: "occupation") //返回的是修改前的值(可選型密末,可用于修改密碼的提示)
//刪除
dict["name"] = nil //刪除某個鍵值對
dict.removeValueForKey("name") //返回刪除掉的值(可選型握爷,類似 updateValue)
if let name = dict.removeValueForKey("name") {
print(name)
}
dict.removeAll() //清空
- 集合
集合 Set: 無序;不重復(fù)严里。
- 聲明
var skillOfA:Set<String> = ["Swift", "OC", "OC"] //若不顯示聲明新啼,則為數(shù)組而非集合
//聲明空的集合
var emptySet1:Set<Int> = []
var emptySet2 = Set<Double>()
Set([1, 2, 3, 1]) //將數(shù)組轉(zhuǎn)為集合
- 常用方法
skillOfA.count
skillOfA.isEmpty
skillOfA.first //由于 Set 是無序的,因此這里是隨機(jī)取一個元素
skillOfA.contains("OC") //是否包含某元素
- 遍歷
for skill in skillOfA {
print(skill)
}
- 比較
let set1:Set = [1, 2, 3]
let set2:Set = [2, 3, 1, 2, 3, 1]
set1 == set2 //true, 重復(fù)的不算
- 增刪改
var skillOfB:Set<String> = ["HTML", "CSS", "Java"]
//插入元素
skillOfB.insert("OC")
skillOfB.insert("Java") //若已有刹碾,則不變
//刪除元素
skillOfB.remove("OC") //返回的是要刪除的元素燥撞,可選型
skillOfB.remove("JS") //nil
if let skill = skillOfB.remove("Java") {
print("成功刪除 \(skill)")
}
- 個性化操作
一些數(shù)學(xué)中的交集、并集等概念迷帜。
var skillOfA:Set<String> = ["Swift", "OC", "OC"]
var skillOfB:Set<String> = ["HTML", "CSS", "Java"]
//并集
skillOfA.union(skillOfB) //二者的并集(二者均不改變)
skillOfA.unionInPlace(skillOfB) //并集(前者改變)
//交集
skillOfA.intersect(skillOfB) //二者的并集(不改變值)
skillOfA.intersectInPlace(skillOfB) //二者的并集物舒,返回給前者
//減法
skillOfA.subtract(skillOfB) //A 減去 A 和 B 的交集(即得到 A 獨有的元素, 不改變 A)
skillOfA.subtractInPlace(skillOfB) //改變 A
//異或
skillOfA.exclusiveOr(skillOfB) //返回二者不同的元素集合
skillOfA.union(["Android", "Java"]) //可以和一個數(shù)組求并集
//子集
skillOfA.isSubsetOf(skillOfA) //子集
skillOfA.isStrictSubsetOf(["OC", "Swift", "Java"]) //OK, 真子集
//超集
skillOfA.isSupersetOf(["Swift"]) //true
skillOfA.isStrictSupersetOf(["OC"]) //true
//相離(兩個集合沒有公共元素)
skillOfA.isDisjointWith(skillOfB) //false
skillOfA.isDisjointWith(["Java"]) //true
函數(shù)
- 聲明
func 函數(shù)名(參數(shù)) -> 返回值類型
//示例代碼 ( 這里的參數(shù)類型為 String?, 返回值類型為 String )
func sayHelloTo(name:String?) -> String {
return "Hello, " + (name ?? "Guest")
}
var nickName:String? = nil
sayHelloTo(nickName) //函數(shù)調(diào)用(注意不要忘記后面的括號)
//無參無參返回值函數(shù)的聲明 (三種方式),無返回值的函數(shù)
func printHello() {
print("Hello")
}
func printHello() -> () {
print("Hello")
}
func printHello() -> Void {
print("Hello")
}
printHello() //調(diào)用(注意不要忘記后面的括號)
- 多參函數(shù)
//聲明多參數(shù)的函數(shù)
func sayName(firstName:String, lastName:String) -> String {
return "Hello! " + firstName + " - " + lastName
}
//注意:調(diào)用多參函數(shù)時戏锹,第二個參數(shù)及以后的參數(shù)名要寫
sayName("Edward", lastName: "Newgate")
//lastNameIs 是外部參數(shù)名(即給外部調(diào)用時的參數(shù)名冠胯。第一個參數(shù)也可設(shè)置外部參數(shù)名)
func sayName2(firstName:String, lastNameIs lastName:String) -> String {
return "Hello! " + firstName + " - " + lastName
}
//lastNameIs 是外部參數(shù)名
sayName2("Edward", lastNameIs: "Newgate")
//忽略參數(shù)的名字(調(diào)用時無需寫該參數(shù)的名字),可在參數(shù)名前加下劃線 _ , 例如
func multiply(num1:Int, _ num2:Int) -> Int {
return num1 * num2
}
multiply(3, 7)
- 有默認(rèn)值的函數(shù)
func multiply(num1:Int, num2:Int = 10) -> Int {
return num1 * num2
}
multiply(3) //30
multiply(3, num2: 7) //21
//也可設(shè)置多個參數(shù)有默認(rèn)值锦针。若如此荠察,則有默認(rèn)值的參數(shù)順序可以改變。
- 變長參數(shù)的函數(shù)
func mean (numbers:Double ... ) -> Double{
var sum:Double = 0
for num in numbers {
sum += num
}
return sum/Double(numbers.count)
}
mean(1) //1
mean(1, 2) //1.5
mean(1, 2, 3) //2
- inout
按引用傳入奈搜,即調(diào)用函數(shù)后值改變悉盆。
func swapTwoInts (inout a:Int, inout _ b:Int) {
// let t:Int = a //二者互換
// a = b
// b = t
(a, b) = (b, a) //使用元組來互換二者更簡潔!
}
var x = 1
var y = 3
swapTwoInts(&x, &y) //這里傳遞的是引用馋吗,調(diào)用后值改變
- 函數(shù)類型
即焕盟,把函數(shù)當(dāng)成一種數(shù)據(jù)類型。
//定義一個函數(shù)
func add(a:Int, _ b:Int) -> Int {
return a + b
}
//可以把函數(shù)當(dāng)做一個變量傳遞 (anotherAdd 的類型為 (Int, Int) -> Int )
let anotherAdd = add
let anotherAdd2:(Int, Int) -> Int = add //也可以顯式聲明宏粤,與前者等效
anotherAdd(1, 2) //調(diào)用
//若只有一個參數(shù)脚翘,參數(shù)類型可以不加括號灼卢,例如:
func sayHelloTo(name:String) -> () {
print("Hello, \(name)")
}
//(String) -> () 類型, 一個參數(shù)可以不加括號,即 String->() 或 String->Void
let sayHello:String->() = sayHelloTo //可以這樣顯式聲明
高階函數(shù)
Swift
的標(biāo)準(zhǔn)數(shù)組支持三個高階函數(shù):map
堰怨,filter
和 reduce
芥玉。
- map
map
用于將每個數(shù)組元素通過某個方法進(jìn)行轉(zhuǎn)換。
//map, Int->_ (任意類型)
//聲明一個數(shù)組
var arr = [15, 21, 35, 49, 62, 77, 83, 86, 86, 92, 93]
//方法一
func changeNum(a:Int) -> Int {
return a + 3
}
//方法二
func isPass(a:Int) -> Bool {
return a > 60 ? true : false
}
arr.map(changeNum) //按照 changeNum 的規(guī)則改變數(shù)組 arr
arr.map(isPass) //按照 isPass 的規(guī)則改變數(shù)組 arr
- filter
filter
用于選擇數(shù)組元素中滿足某種條件的元素备图。
//filter, Int->Bool
func fail(a:Int) -> Bool {
return a < 60
}
arr.filter(fail)
- reduce
reduce
方法把數(shù)組元素組合計算為一個值灿巧。
func add(num1:Int, _ num2:Int) -> Int{
return num1 + num2
}
arr.reduce(0, combine: add) //數(shù)組求和。第一個參數(shù)為初始值
arr.reduce(0, combine: +) //或者這么寫揽涮,與前者等效
func concatenate(str:String, num:Int) -> String {
return str + String(num) + " "
}
arr.reduce("", combine: concatenate) //
閉包
閉包(Closure):本質(zhì)是函數(shù)抠藕,類似匿名函數(shù)或 Block。
使用閉包可以對函數(shù)進(jìn)行簡化蒋困,例如:
func biggerNumerFirst(a:Int, _ b:Int) -> Bool {
// if a > b {
// return true
// }
// return false
return a > b //與前者等效
}
arr.sort(biggerNumerFirst) //變?yōu)閺拇蟮叫∨判?
//使用閉包可以這么寫:
arr.sort({ (a:Int, b:Int) -> Bool in
return a > b
})
//還可以進(jìn)行如下簡化:
arr.sort({ (a:Int, b:Int) -> Bool in return a > b }) //一行代碼的可以這么寫
arr.sort( {a, b in return a > b} ) //因為 sort 中函數(shù)的類型是固定的盾似,所以類型可以不寫
arr.sort( {a, b in a > b} ) //return 也可以不寫
arr.sort( {$0 > $1} ) //更簡潔 (使用默認(rèn)的命名)
arr.sort(>) //OMG!
//注意代碼簡化和可讀性之間的平衡,并非越簡單越好雪标。
//Trailing Closure (函數(shù)為最后一個參數(shù))
arr.sort(){a, b in return a > b}
arr.sort(){ a, b in
return a > b
}
arr.sort{ a, b in //() 可以省略
return a > b
}
注意:閉包和函數(shù)是引用類型(之前的基本類型是值類型)零院,即調(diào)用后會改變原先的值。
func runningMeters(metersPerDay:Int) -> () -> Int {
var totalMeters = 0
return { //返回的是閉包
totalMeters += metersPerDay
return totalMeters //每天跑多少
}
}
var planA = runningMeters(2000)
planA() //注意后面的小括號村刨。告抄。。
planA() //再次調(diào)用會累加
var planB = runningMeters(3000)
planB()
var anotherPlanB = planB
anotherPlanB() //這樣也會累加
planB() //說明函數(shù)和閉包是引用類型
//也可以使用 let 關(guān)鍵字嵌牺,其含義是 planC 不能再改變打洼,而非 runningMeters 不能改變
let planC = runningMeters(5000)
planC()