Swift學習筆記--為代碼的執(zhí)行做個決定

為代碼的執(zhí)行做個決定

[TOC]

和其他的編程語言一樣鹿寻,為了能夠控制程序的執(zhí)行路徑宏粤,Swift提供了我們熟悉的循環(huán)和分之判斷語句荔燎。首先我們先快速的過一遍他們的基本用法堵漱。

條件分支語句

第一個要介紹的,是if...else if...else...莱找。這是幾乎每種語言都支持的分支表達方式酬姆,其中else ifelse都是可選的部分嗜桌,它們可以單獨和if搭配形式各種分支條件的判斷奥溺。基本上骨宠,看到代碼浮定,我們就可以直接了解這類判斷的含義了。

var light = "red"
var action = ""

if light == "red" {
    action = "stop"
}
else if light == "yellow" {
    action = "caution"
}
else if light == "green" {
    action = "go"
}
else {
    action = "invalid"
}

在上面這個紅綠燈的代碼里层亿,我們不斷根據(jù)light的值桦卒,設置了變量action的值,它很簡單匿又。但通常方灾,我們還是更多會使用if...else...表示非黑即白這樣的簡單關系。

對于上面這種存在多種可能性的情況碌更,在Swift里裕偿,我們通常還是會使用switch...case...來表示,它比if...else...更安全痛单,也更有更好的表意:

switch light {
    case "red":
        action = "stop"
    case "yellow":
        action = "caution"
    case "green":
        action = "go"
    default:
        action = "invalid"
}

這里嘿棘,我們使用switch...case...表達了和之前的if...else...相同的語義。但是旭绒,它更明確的表達了當light的值(switch)為各種情況(case)時鸟妙,我們應該采取哪些措施,這樣的概念挥吵。

但和C++/Java這樣語言相比重父,Swift中的switch...case...也有一些自己獨特的地方:

首先,case語句必須exhausitive忽匈,也就是說坪郭,必須覆蓋switch后面出現(xiàn)的表達式的所有情況,否則會導致編譯錯誤.

當你不需要對列出case的其他情況作出處理時脉幢,你也要在default分支寫上一句break歪沃,明確表示你考慮到了其他的情況嗦锐,只是你不需要更多額外處理而已。

其次沪曙,每個case語句不會自動“貫通”到下一個case奕污,因此我們也無需在每個case最后一行寫break表示結束;

最后液走,當我們要在一個case里匹配多個條件的時候碳默,可以使用逗號把多個條件分開,以上,就是和分支條件相關的兩個最基本的場景和用法缘眶,接下來嘱根,我們了解循環(huán)。

循環(huán)控制語句

第一個要介紹的巷懈,是for element in collection/range该抒,我們可以用它來方便的遍歷一個集合類型或者范圍:

let vowel = ["a", "e", "i", "o", "u"]

for char in vowel {
    print(char)
}
// aeiou

for number in 1...10 {
    print(number)
}
// 12345678910

第二個循環(huán)的方式是while,它有前置判斷和后置判斷兩種形式顶燕,基本上保留了原汁原味的C用法:

// while
var i  = 0
while i < 10 {
    print(i)
    i += 1
}

// do ... while
repeat {
    print(i)
    i -= 1
} while i > 0

在這兩類循環(huán)里凑保,我們都可以用continue來停止執(zhí)行當前循環(huán)中的語句,立即開始下一次循環(huán)涌攻。例如欧引,打印所有的偶數(shù):

for number in 1...10 {
    if number % 2 != 0 { continue }
    print(number)
}
// 2 4 6 8 10

在這個例子里,如果number是奇數(shù)恳谎,就會執(zhí)行到continue芝此,當前循環(huán)就停止并自動進入下一次循環(huán)了。

或者因痛,我們也可以使用break來終止整個循環(huán)婚苹。例如,值大于8時婚肆,就終止循環(huán):

for number in 1...10 {
    if number > 8 { break }
    print(number)
}
// 1 2 3 4 5 6 7 8

使用簡單的樣式匹配

現(xiàn)實環(huán)境中租副,我們需要的判斷條件可能比那些演示的例子復雜的多。為此较性,Swift從函數(shù)式編程中借鑒了一些樣式匹配的方式用僧,幫助我們構建表意豐富又易于維護的代碼。

匹配值的方式

為了演示各種樣式匹配的方式赞咙,我們先定義一個tuple责循,表示平面直角坐標系中的原點:

let origin = (x: 0, y: 0)

當我們要判斷某個點是否是原點的時候,最原始的方式攀操,是這樣的:

let pt1 = (x: 0, y: 0)
if pt1.x == 0 && pt1.y == 0 {
    print("@Origin")
}

當然院仿,這樣判斷xy坐標是否相等并不能讓人滿意,寫起來非常麻煩。實際上歹垫,我們還可以這樣:

if case (0, 0) = pt1 {
    print("@Origin")
}

我們可以用case 匹配的值 = 要檢查的對象的方式剥汤,對要檢查的對象進行判斷。在我們的例子里排惨,判斷的就是pt1是否等于原點吭敢。

除了用在if中匹配值,我們當然也可以在switch的case分支里暮芭,匹配特定形式的值:

switch pt1 {
case (0, 0):
    print("@Origin")
case (_, 0):
    print("on x axis")
case (0, _):
    print("on y axis")
case (-1...1, -1...1):
    print("inside 2x2 square")
default:
    break;
}

在上面這個例子里鹿驼,除了用case (0, 0)表示匹配原點值之外,還可以用(_, 0)(0, _)表示忽略掉_的部分辕宏,僅對tuple中某一部分的值進行匹配畜晰,或者,在tuple的每一個成員位置瑞筐,使用range operator匹配值的某個范圍凄鼻。

除了把case用于條件分支語句,我們還可以用于循環(huán)語句面哼,用于進一步控制循環(huán)條件野宜,例如:

let array1 = [1,1,2,2,2]

for case 2 in array1 {
    print("found two")
}

在上面這個例子里扫步,當遇到數(shù)組中值為2的元素時魔策,我們向控制臺打印了一行話,因此河胎,print一共會打印3次闯袒。

把匹配的內容綁定(value binding)到變量

除了在 case中使用各種形式的具體值之外,我們還可以把匹配到的內容直接綁定到變量上游岳,這樣我們就可以再相應的處理代碼中直接使用它們政敢,例如:

switch pt1 {
    case (let x, 0):
        print("(\(x),0) is on x axis")
    case (0, let y):
        print("(0,\(y)) is on y axis")
    default:
        break;
}

在上面這個例子里,我們把之前_的部分換成了let xlet y胚迫,這樣喷户,同樣是匹配在坐標軸上的點,這次访锻,我們就可以在對應的case中褪尝,直接訪問匹配到的值了。我們管這樣的形式期犬,叫做value binding河哑。

除了直接綁定變量自身的值之外,我們還可以用類似的形式綁定enum中的關聯(lián)值龟虎。例如璃谨,我們先定義一個表示方向的enum

enum Direction {
    case north, south, east, west(abbr: String)
}

let west = Direction.west(abbr: "W")

為了演示,我們給.west添加個了一個associated value,表示方向的縮寫佳吞。然后拱雏,我們既可以像這樣來判斷enum值自身:

if case .west = west {
    print(west) // west("W")
}

此時,print打印的就是enum case的值底扳。我們也可以這樣來直接綁定westassociated value

if case .west(let direction) = west {
    print(direction) //W
}

此時古涧,print打印出來的值,就直接是字符“W”了花盐。當然羡滑,case這樣的用法,在switch的分支中算芯,也是完全可以的柒昏。

自動提取optional的值

除了綁定enum的associated value之外,我們還可以使用case來自動提取optional類型的非空值:

let skill: [String?] = ["Swift", nil,"PHP","JavaScript",nil]

for case let skill? in skills {
    print(skill) // Swift PHP JavaScript
}

在我們的例子里熙揍,skills包含了5個元素职祷,其中兩個是nil,當我們用case let skill?這樣的形式來綁定optional值的時候届囚,Swift就會自動提取每一個非nil的元素有梆,因此,print會輸出“Swift PHP JavaScript”意系。

自動綁定類型轉換的結果

最后一類基本的樣式匹配規(guī)則是自動綁定類型轉換的結果泥耀。首先,我們創(chuàng)建一個[Any]

let someValue: [Any] = [1, 1.0, "One"]

當我們遍歷someValues,并且要根據(jù)不同類型的數(shù)組元素分別做一些操作的時候蛔添,可以這樣:

for value in someValues {
    switch value {
    case let v as Int:
        print(Interger \(v))
    case let v as Double:
        print(Double \(v))
    case let v as String:
        print(String \(v))
    default:
        print("Invalid value")
    }
}
// Integer 1
// Double 1.0
// String One

在上面的例子中痰催,我們使用了case let Variable as Type的方式,把類型轉換成功的結果迎瞧,綁定在了變量V上夸溶。這樣,我們就可以在對應的case里凶硅,訪問到轉換成功的值了缝裁。

或者,如果你僅僅想判斷類型足绅,而不需要知道具體內容的話捷绑,還可以使用更簡單的is操作符:

for value in someValues {
    switch value {
    case is Int:
        print("Integer")
    // omit for simplicity...
}

使用高級樣式匹配方式

使用where約束條件

除了使用具體的數(shù)值對循環(huán)或分支條件進行約束外,我們還可以使用where進行更復雜的約束编检。先來看一個簡單的例子:

for i in 1...10 where i % 2 == 0 {
    print(i)
}

這里我們在for循環(huán)里使用了where限定了進入循環(huán)的值必須是偶數(shù)胎食。我們還可以把where用在更復雜的value binding語句里。例如允懂,我們假設定義下面的enum表示手機電量

enum Power {
    case fullyCharges
    case normal(percentage: Double)
    case outOfPower
}

然后在定義一個battery表示手機電池

let battery = Power.normal(percentage: 0.1)

這樣厕怜,我們就可以在綁定.normalassociated value的同時,使用where進一步約束它的關聯(lián)值:

switch battery {
    case .normal(let precentage) where percentage <= 0.1":
        print("almost out of power")
    case .normal(let percentage) where percentage >= 0.8:
        print("almost fully power")
    case .fullyCharges, .outOfPower:
        print("Fully charged or out of power")
    default:
        break
}

上面的case語句中,batteryfullyChargesoutOfPower我們使用逗號分隔粥航,表示邏輯或的概念琅捏,逗號也可以用在if中表示邏輯與的概念,例如為了處理之前電量低的情況递雀,我們還可以用if這樣來實現(xiàn):

if case .normal(let percentage) == battery, case 0...0.1 = percentage {
    print("Almost out of power")    
}

在上面的代碼里柄延,第一個if case使用value binding讀取了battery中.normal的associated value。接下來缀程,第二個case進一步約束了第一個case中關聯(lián)到的值小于10%的情況搜吧。

使用tuple簡化多個條件的比較

有時,我們需要在if中同時比較多個條件杨凑。假設滤奈,我們有一對用戶名和密碼:

let username = "11@boxue.io"
let password = 11111111

當我們要同時比較這兩個值時,最普通的寫法撩满,就是在if中使用邏輯與(&&)操作符:

if username == "11@boxue.io" && password == 11111111 {
    print("correct")
}

如果你不喜歡在if中并列多個比較語句蜒程,我們還可以用case臨時生成一個tuple,并且伺帘,讓它和username / password進行比較:

if case ("11@boxue.io", 11111111) = (username,password) {
    print("correct")
}

理解樣式匹配的實現(xiàn)方式

首先昭躺,當要匹配的變量和樣式的類型相同,并且對應的類型實現(xiàn)了Equatable protocol時伪嫁,就直接使用對應類型的==操作符進行匹配领炫。例如我們之前比較用戶名和密碼的例子:

let username = "11@boxue.io"
let password = 11111111

if case ("11@boxue.io", 11111111) = (username, password) {
    print("correct")
}

這里,就直接使用了Tuple類型的比較操作符礼殊。

其次驹吮,如果樣式和要匹配的變量類型不同针史,或對應類型沒有實現(xiàn)Equaltable protocol時晶伦,Swift會使用~=操作符進行比較。當這個操作符返回true時啄枕,就認為條件匹配婚陪,否則就認為不匹配。因此频祝,為了判斷某個數(shù)值是否在某個范圍里泌参,Swift標準庫中實現(xiàn)了Range ~= Value這種形式的比較,但是常空,卻沒有實現(xiàn)Value ~= Range這樣的版本沽一。

因此,當我們寫成case percentage = 0...0.1時漓糙,編譯器就會因為找不到對應的操作符而報錯了铣缠。不過,由于這個操作符是可以自定義的,因此蝗蛙,我們可以通過重載它蝇庭,來實現(xiàn)上面的功能:

func ~=<T>(value: T, pattern: ClosedRange<T>) -> Bool {
        return pattern.contains(value)
}

為了能匹配不同的類型,我們把~=定義為了一個泛型函數(shù)捡硅。它的第一個參數(shù)表示~=的左操作數(shù)哮内,按照我們的例子,應該是一個值壮韭;第二個參數(shù)表示~=的右操作數(shù)北发,它是一個ClosedRange<T>。在它的實現(xiàn)里喷屋,我們只要調用ClosedRangecontains方法鲫竞,就可以實現(xiàn)“是否包含某個值”這樣的語義了。

而當我們重載了這個~=方法之后逼蒙,之前發(fā)生編譯錯誤的語句就可以正常工作了从绘。我們也可以通過類似的方法,為自定義類型添加各種樣式匹配規(guī)則是牢。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末僵井,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子驳棱,更是在濱河造成了極大的恐慌批什,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件社搅,死亡現(xiàn)場離奇詭異驻债,居然都是意外死亡,警方通過查閱死者的電腦和手機形葬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門合呐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人笙以,你說我怎么就攤上這事淌实。” “怎么了猖腕?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵拆祈,是天一觀的道長。 經(jīng)常有香客問我倘感,道長放坏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任老玛,我火速辦了婚禮淤年,結果婚禮上犁珠,老公的妹妹穿的比我還像新娘。我一直安慰自己互亮,他們只是感情好犁享,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著豹休,像睡著了一般炊昆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上威根,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天凤巨,我揣著相機與錄音,去河邊找鬼洛搀。 笑死敢茁,一個胖子當著我的面吹牛,可吹牛的內容都是我干的留美。 我是一名探鬼主播彰檬,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谎砾!你這毒婦竟也來了逢倍?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤景图,失蹤者是張志新(化名)和其女友劉穎较雕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挚币,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡亮蒋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了妆毕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片又谋。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡抡驼,死狀恐怖武花,靈堂內的尸體忽然破棺而出短纵,到底是詐尸還是另有隱情,我是刑警寧澤闰蛔,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站图柏,受9級特大地震影響序六,放射性物質發(fā)生泄漏。R本人自食惡果不足惜蚤吹,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一例诀、第九天 我趴在偏房一處隱蔽的房頂上張望随抠。 院中可真熱鬧,春花似錦繁涂、人聲如沸拱她。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秉沼。三九已至,卻和暖如春矿酵,著一層夾襖步出監(jiān)牢的瞬間唬复,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工全肮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留敞咧,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓辜腺,卻偏偏與公主長得像休建,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子评疗,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理丰包,服務發(fā)現(xiàn),斷路器壤巷,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • 本章將會介紹 控制流For-In 循環(huán)While 循環(huán)If 條件語句Switch 語句控制轉移語句 continu...
    寒橋閱讀 717評論 0 0
  • 組卷網(wǎng)胧华,高考資源網(wǎng)寄症,中學學科網(wǎng),菁優(yōu)網(wǎng)我要自學網(wǎng)矩动。
    ff33440ed08d閱讀 334評論 0 1
  • 這條文章教大家判斷零售行業(yè)到底是該走線上還是走線下悲没。 在零售行業(yè)篮迎,很多人說線下才有機會,連馬云都說未來純電商的日子...
    左右文摘閱讀 939評論 0 1
  • 涼拖破了一條長長的口子示姿,突然想起了小時后焊涼鞋的事情甜橱。 小時后的涼鞋,男孩穿的主要是灰色塑料制成栈戳,不知道什么材質岂傲,...
    liyongthethird閱讀 632評論 0 0