Swift 語法(二)

可選型

可選型是 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堰怨,filterreduce芥玉。

  • 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()

玩兒轉(zhuǎn)Swift 2.0(第二季)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市逆粹,隨后出現(xiàn)的幾起案子募疮,更是在濱河造成了極大的恐慌,老刑警劉巖僻弹,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阿浓,死亡現(xiàn)場離奇詭異,居然都是意外死亡蹋绽,警方通過查閱死者的電腦和手機(jī)芭毙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蟋字,“玉大人,你說我怎么就攤上這事扭勉∪到保” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵涂炎,是天一觀的道長忠聚。 經(jīng)常有香客問我设哗,道長,這世上最難降的妖魔是什么两蟀? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮赂毯,結(jié)果婚禮上战虏,老公的妹妹穿的比我還像新娘。我一直安慰自己党涕,他們只是感情好烦感,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著膛堤,像睡著了一般手趣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上肥荔,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天绿渣,我揣著相機(jī)與錄音,去河邊找鬼燕耿。 笑死中符,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缸棵。 我是一名探鬼主播舟茶,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼堵第!你這毒婦竟也來了吧凉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤踏志,失蹤者是張志新(化名)和其女友劉穎阀捅,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體针余,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡饲鄙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了圆雁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忍级。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖伪朽,靈堂內(nèi)的尸體忽然破棺而出轴咱,到底是詐尸還是另有隱情趣效,我是刑警寧澤暮芭,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布适揉,位于F島的核電站斗蒋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏戈稿。R本人自食惡果不足惜西土,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鞍盗。 院中可真熱鬧需了,春花似錦、人聲如沸橡疼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽欣除。三九已至住拭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間历帚,已是汗流浹背滔岳。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留挽牢,地道東北人谱煤。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像禽拔,于是被迫代替她去往敵國和親刘离。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一.循環(huán) 常見的循環(huán)有:for/while/do while 1.for循環(huán) 1.1 OC中的for循環(huán)寫法 1....
    尕小天閱讀 573評論 7 6
  • 本章將會介紹 閉包表達(dá)式尾隨閉包值捕獲閉包是引用類型逃逸閉包自動閉包枚舉語法使用Switch語句匹配枚舉值關(guān)聯(lián)值原...
    寒橋閱讀 1,559評論 0 3
  • 2014年的蘋果全球開發(fā)者大會(WWDC),當(dāng)Craig Federighi向全世界宣布“We have new ...
    yeshenlong520閱讀 2,289評論 0 9
  • 我一直認(rèn)為“不解相思”與“不解風(fēng)情”是異曲同工野来,當(dāng)然到現(xiàn)在也是這么想的恼除。 我不懂得人們口中心中的“愛情”,他們告訴...
    花少顏閱讀 199評論 4 0
  • 本人承諾曼氛,文章內(nèi)容為原創(chuàng)豁辉。 上一章 壹 小白醒來的時候,已經(jīng)是半夜時分舀患。 雖然什么都看不到徽级,但是能隱約聽到外面?zhèn)鱽?..
    流沙小妖怪閱讀 804評論 8 15