--- title: 'Swift - 判斷、集合、迴圈' disqus: kyleAlien --- Swift - 判斷、集合、迴圈 === ## Overview of Content [TOC] ## Swift 表達結構 在這裡我們要建立幾個名詞的概念,陳述式、表達式、變數、常數... 等等,它們都與程式密切的關係 :::info 這些名詞可以讓我們更好的分析、認識程式,但注意不要糾結於這些名詞,這些名詞可能會因為語言不同而有不同的描述方式 ::: ### Swift 程式 - 基本組件 * Swift 程式是由各種不同元素組成,其主要組成元素如下(請配合以下範例一起對照) | 元素名 | 特性 | 補充 | | - | - | - | | 變數(variable) | 變數是一種可以在運行時改變的數據 | - | | 常數(constant) | 常數在運行時不可修改 | 設定後就永遠不可修改 | | 字面值(literal) | 字面值就是有意義的 “數據”,這些數據有各種不同型態(String, Bool... 等等) | - | | 型態(type) | 標註變數、常數的類型,說明要如何解釋這個數據 | - | | 陳述式(statement) | 程式準備執行的動作 | for-in, if... 等等,會有許多不同特性 | | 表達式(expression) | 負責回傳結果值 | - | | 宣告(declaration) | 負責將一個新的名字(使用者定義)導入程式 | 可以宣告變數、常數、函數、結構 ... 等等 | ```swift= // *變數* // 變數格式:var <變數名> : <型態> = <字面值> // 對照:變數名 myString // 型態 String // 字面值 "Hello world" var myString : String = "Hello world" // *變數* var isShowing : Bool = true // *常數* // 常數格式:var <變數名> : <型態> = <字面值> // 對照:變數名 NAME // 型態 String(語字自動推導) // 字面值 "Hello world" let NAME = "Kyle" // *陳述式*(判斷) if isShowing { // *陳述式*(循環迴圈) for tmp in 1...5 { // 函數 print("\(myString): \(tmp)") } } // *表達式* (最終輸出一個結果) myString += ", Yoyo" // 函數 print("\(NAME), \(myString)") ``` > 執行結果 > > ![](https://i.imgur.com/tZnsNqT.png) ### 運算子 Operator * 建構組件 運算子 (Operator) 在每個程式語言中都相當重要,可以透過它檢查、修改資料;它的通常有兩種方式表達 * **符號**:`+`、`-`、`*`... 等等 * **片語**:`inc`、`dec` ... 等等(通常用於運算符重載,每個運算符都有對應的片語,可以參考 ) > 這裡不說明片語 * 運算子分類:如下表 | 分類 | 說明 | 舉例 | | -------- | -------- | -------- | | 一元 (unary) | 運算一個數值 | -1 | | 二元 (binary) | 運算兩個值 | 1 + 2 | | 三元 (ternary) | 先判斷再決定 | value ? 1 : 666 | :::info * 運算子運作的 Scope 上面範例來說都是數字運算,然而運算子不只可以運作在數字上 (只是常見);它還可以運作在字串,甚至 **只要符合某些條件也可以運作在物件上** ::: * 下表為幾個常見的數學運算子 | 運算子 | 說明 | 舉例 | | - | - | - | | + | 加法 | 1 + 2 = 3 | | - | 減法 | 10 - 8 = 2 | | * | 乘法 | 11 * 3 = 33 | | / | 除法 | 6 / 3 = 2 | | % | 取模 (取餘數) | 10 / 7 = 3 | ```swift= print("1 + 2 = \(1 + 2)") print("10 - 8 = \(10 - 8)") print("11 * 3 = \(11 * 3)") print("6 / 3 = \(6 / 3)") print("10 % 7 = \(10 % 7)") ``` > ![](https://i.imgur.com/BK3pfCk.png) :::success * **表達式(expression)** 運算子最終都會產生一個值,對於有最終產值的行為,我們都稱為表達式(expression) ::: :::warning * **空格不可混用** Swift 中空格與運算子之間不可混用否則會編譯不過 ```swift= var result = 0 // Error result = 12 /4 result = 12/ 4 // OK result = 12 / 4 result = 12/4 ``` ::: * 等號 `=` 也是運算子(**指定運算子**),所有出現在 `=` 後的值都是 **字面值(`literal`)**,這個字面值不只是數字,也可以是其他數據 ### Swift 基礎型態 * **++型態++** 對於程式語言是一種強硬的設計!但同時也保證其安全性;在 Swift 中有以下方式可以定義型態 1. 宣告變數時,直接指定型態 ```swift= var myVariable1: Int = 123 ``` 2. 宣告變數時,給定數值,讓編譯器自動推導 ```swift= var myVariable2 = 77.0 ``` 3. 宣告變數,並指定型態,延遲指定變數 ```swift= var myVariable3: String myVariable3 = "iOS" ``` :::danger * 延遲指定注意 1. 這裡雖然延遲指定變數,但是在使用該變數時編譯器會判斷你是否有指定變數,如果沒指定會導致編譯不過 > ![](https://i.imgur.com/IyJXCi9.png) 2. 延遲指定變數,之後要指定也要是相同類型才能指定 > ![](https://i.imgur.com/pX2vJzT.png) ::: * Swift 的基礎型態包括: > Swift 還提供了許多高級型態,例如陣列、字典、元組等,可以更方便地處理複雜的數據結構 1. **整數型態**:用於表示整數數值,包括 `Int`、`UInt8`、`UInt16`、`UInt32`、`UInt64`、`Int8`、`Int16`、`Int32`、`Int64` ```swift= var myInt: Int = 10 ``` :::info * **Int 怎麼分這麼多不同型態**? 我們最常用的 `Int` 型態會依據我們使用裝置的硬體(CPU 總線)來決定該型態的大小(可能 32 or 64 bit) 而其他型態則是我們清楚指明要使用的類型,其可能包括有符號 (Signed)、無符號 (Unsignd)的不同大小 ::: 2. **浮點型態**:用於表示浮點數值,包括 `Float`、`Double`;**swift 預設型態為 Double** > 我們可以透過 type 來判斷其類型 ```kotlin= var myFloat : Float = 10.0 print(type(of: myFloat)) var myDobule : Double = 10.0 print(type(of: myDobule)) print("Default: \(type(of: 10.0))") ``` > ![](https://i.imgur.com/vizRsiD.png) 3. **Bool 布林型態**:用於表示邏輯值,包括 `true` 和 `false` ```swift= var myBool : Bool = true var myBool_1 : Bool = false ``` 4. **String 字符串型態**:用於表示文字,包括 `String` ```swift= var myString: String = "Hello World" ``` 5. **Character 字符型態**:用於表示單個字符,包括 `Character`;Swift 不使用這個符號 `'` 描述單個字符 ```swift= var myChar : Character = "A" ``` 6. **選擇型態**:用於表示一個值或者沒有值(也就是可以沒有值的意思),包括 `Optional` ```swift= var myOptional : Optional = "ABC" // 非 Optional 型態不可設定為 nil myOptional = nil ``` > Optional 型態的細節之後再說明 ## 集合 Swift 有一系列用於儲存數據的型態(類型),這些型態就稱為 **集合**,其主要集合型態為 ^1.^ Array, ^2.^ Set, ^3.^ Dictionary 它們的特性都不相同 :::warning 集合中可以有多個數據,但 **集合中的數據必須要相同類型** ::: ### Array - 順序性 * **Array(陣列)的特性**:**有順序性、數據可以重複、透索引值取值**;其創建方式如下 > Array 又稱之為陣列 :::success 索引值從 0 開始算 ::: * 數據格式:[ <數據>* ] ```swift= let myArray : Array = [1, 2, 9, 3, 7, 9] // 其型態也可以寫出來 let myArray2 : [Int] = [1, 2, 9, 3, 7, 9] ``` * **Array 常用 API**: | 功能 | API | | - | - | | Array 當前數據數量 | count | | Array 是否為空 | isEmpty | | 新數據加到後方 | append(value) | | 新數據插入指定位置 | insert(value, index) | | 移除指定位置數據 | remove(index) | ```swift= var myArray : [Int] = [1, 2, 3] print("index of 0: \(myArray[0])") myArray.append(100) print("index of 3: \(myArray[3])") myArray.insert(99, at: 3) print("index of 3: \(myArray[3])") if !myArray.isEmpty { print("Current count, \(myArray.count)") } print("Before remove, index of 0: \(myArray[0])") myArray.remove(at: 0) print("After remove, index of 0: \(myArray[0])") ``` > ![](https://i.imgur.com/gWqu8vH.png) ### Set - 不可重複性 * **Set 的特性**:**無序性、數據唯一、無法透過索引取值**;其創建方式如下 * 數據格式: 1. Set([ <數據>* ]) ```swift= let mySet1 = Set([3, 3, 1, 4, 7, 9, 1]) ``` 2. 宣告類型 Set = [ <數據>* ] ```swift= let mySet2 : Set = [3, 3, 1, 4, 7, 9, 1] ``` * **Set 常用 API**: | API | 功能 | |:---------------| ------------------------ | | count | Array 當前數據數量 | | isEmpty | Array 是否為空 | | insert(value) | 插入新數據 | | contains(value) | 判斷集合內是否有某個數據 | | remove(index) | 移除指定數據 | ```swift= var mySet : Set = [9, 2, 3, 5, 5, 6, 1, 5] mySet.insert(8) if mySet.contains(9) { mySet.remove(9) } if !mySet.isEmpty { print("Current count, \(mySet.count)") for item in mySet { print("Set item: \(item)") } } ``` :::warning 1. 從結果可以發現,Set 不會儲存重複相同的數據 > 以上 5 雖然重複,不過它最終在 Set 中只有一個 2. Set 集合是無法直接取得數據的,所以這邊使用 for 循環遍歷集合 ::: > ![](https://i.imgur.com/Bf30fRB.png) ### Dictionary - 鍵值 * **Dictionary 的特性**:**無序性、數據透過 key/Value 的方式儲存**;其創建方式如下 * 數據格式:[ <Key : Value\>* ] ```swift= let myDictionary = [ 1 : "A", 2 : "B", 3 : "C", 4 : "D" ] let myDictionary2: [Int: String] = [ 1 : "A", 2 : "B", 3 : "C", 4 : "D" ] ``` :::info * 可以指定一個空 Dictionary,不過要先宣告類型,否則編譯器會不知道該變數的類型 ```swift= let emptyDictionary : [String: Float] = [:] ``` ::: * **Dictionary 常用 API**: | 功能 | API | | - | - | | count | Dictionary 當前數據數量 | | isEmpty | Dictionary 是否為空 | | updateValue(Value, Key) | 更新指定 Key 的數據 | | [Key] = Value | 更新指定 Key 的數據 | | removeValue(key) | 用 Key 來移除 Dictionary 中的數據 | ```swift= var myDictionary3 = [ 1 : "A", 2 : "B", 3 : "C", 4 : "D" ] if !myDictionary3.isEmpty { print("Count: \(myDictionary.count)") } myDictionary3.updateValue("AAA", forKey: 1) print("The 1 value is \(myDictionary3[1])") myDictionary3[1] = "ABCDEFG" print("The 1 value is \(myDictionary3[1])") myDictionary3.removeValue(forKey: 2) print("The 2 is \(myDictionary3[2])") ``` > ![](https://i.imgur.com/9ACZbq9.png) ### Tuple 集合 * Tuple (元組) 集合可以讓多個值儲存在單一變數、常數中,其中的元素可以修改,而不會像有陣列之類的負擔 > 並且它可以特別指定元素的名稱 :::info * 這裡的負擔是指啥? * Array 通常需要指定大小或容量,並且需要連續的記憶體空間來存儲元素。當陣列的大小需要改變時,可能需要重新分配記憶體空間,把現有的元素拷貝到新的位置上,這樣的操作需要額外的時間和資源 * 相較之下,Tuple 可以讓多個值以 **有序** 的方式存在單一變數、常數中,^1.^ 不需要指定容量,也 ^2.^ 不需要連續的記憶體空間 因此,使用元組可以減少記憶體的使用,並且在運行時不需要額外的內存分配和拷貝操作,因此可以更加高效 ::: * Tuple 可以指定 & 不指定其元素的名稱 ```swift= var myTuple = (10, 20) // tuple 元素可修改 myTuple.0 = 55 // 不指定時按照 index 取得數據 print("my tuple , 0: \(myTuple.0)") print("my tuple , 1: \(myTuple.1)") // 可以指定元素名稱 var myTuple2 = (a: 100, 200) // 按照元素名稱取得數據 print("my tuple 2, a: \(myTuple2.a)") // 沒指定的話,就按照 index 取得 print("my tuple 2, 1: \(myTuple2.1)") ``` > ![](https://i.imgur.com/iiUrJmK.png) ## 陳述式 - Expression 上面我們有提到陳述式(Expression)是一個程式語言的基本組成,它可以幫你進行迴圈、判斷... 等等功能; :::success 這種控制程式運行的手法常被稱之為:控制流、結構化 ::: * swift 常用 Expression 如下 1. 判斷條件:`if`, `switch` 2. 迴圈:`for`, `for-in`, `while` ,`repeat-while` ### 判斷條件 - if * 使用 `if` 的前提是,真假判斷(Bool 表達式)也就是說要有一個 True、False 的輸出,才能使用 `if` 判斷;其格式如下 ```swift= if(真假判斷) { // 成立後執行的程式 } else { // 不成立後執行的程式 } // 使用空格就可以省略 `()`--------------------------- if 真假判斷 { // 成立後執行的程式 } else { // 不成立後執行的程式 } ``` * 使用範例: ```swift= var showMsg: Bool = true if showMsg { print("Hello World") } else { print("What?") } ``` > ![](https://i.imgur.com/raCjkIB.png) * 同一個 `if` 判斷,可以用 `else if` 增加更多的條件判斷,也可以讓其他人明白該判斷相關的條件不止一個 ```swift= var mylist = [1, 2, 3] if mylist.isEmpty { print("I get empty list.") } else if mylist.count == 1 { print("I get the list, the size is 1.") } else if mylist.count == 2 { print("I get the list, the size is 2.") } else if mylist.count == 3 { print("I get the list, the size is 3.") } else { print("I get the big size of list.") } ``` > ![](https://i.imgur.com/S8YCfll.png) ### 判斷條件 - switch * 使用 `switch` 同樣是判斷條件,但是它會把自動把需要判斷的數據帶入每個不同的條件狀況 (`case`),看起來會更加的簡潔;其格式如下 ```swift= switch(數值) { case 條件狀況: // 符合條件狀況則執行這 default: // 以上狀況皆不符合則執行這 } // 使用空格就 switch 可以省略 `()`--------------------------- switch 數值 { case 條件狀況: // 符合條件狀況則執行這 default: // 以上狀況皆不符合則執行這 } ``` :::success * `if` vs. `switch` 使用 兩者沒有絕對要使用哪一個(基本上憑經驗判斷),但可以注意到的是 `if` 可以取多種方案多個判斷,而 `switch` 更針對一種方案多個判斷 > switch 更指定,長遠來看更好維護 ::: * 使用範例: ```swift= var mylist = [1, 2] // 指定要判斷的方案 switch mylist.count { // 以下在各種 case 中判斷 case 0: print("I get empty list.") case 1: print("I get the list, the size is 1.") case 2: print("I get the list, the size is 2.") case 3: print("I get the list, the size is 3.") default: print("I get the big size of list.") } ``` > ![](https://i.imgur.com/xaM7Zx3.png) :::warning * **Swift 與其他語言的不同**: 它仍然有 `break`、`continue`,不過在 case 自然結束時不需要添加,只有在需要中途跳出時才需添加 ```swift= switch mylist.count { case 0: print("I get empty list.") case 1, 2: if mylist[0] == 1 { print("list element of 0 if 1") // 跳出該 case break } // 不會被執行到 print("I get the list!") default: print("I get the big size of list.") } ``` > ![](https://i.imgur.com/ECkoSKb.png) ::: ### 迴圈 - for-in / foreach * `for-in` 陳述式用來遍歷集合(Collection)數據,其格式如下 ```swift= // 遍歷 range 時,`constains` 數值就會一直更新 for constains in range { // other code } ``` * `for-in` 使用範例 ```swift= let array = [1, 2, 55, 11, 88] for tmp in array { print("Current value = \(tmp)") } ``` > ![](https://i.imgur.com/RsWuY0P.png) :::info * `foreach` 是集合的一種 API 可以簡化 `for-in`,使用方式如下: ```swift= let array = [1, 2, 55, 11, 88] array.forEach { // 取直改成使用 `$0` print("Current value = \($0)") } ``` > 輸出同上 ::: :::success * swift 沒辦法自己控制回圈的 index,所以要逆向搜尋的話就需要使用 `resversed()` 方法 ```swift= for j in (0...times).reversed() { // do nothing } ``` ::: ### 迴圈 - while / repeat-while * `while` 陳述式同樣可以用來遍歷數據,通常用使用在不清楚回圈需循環幾次時的狀況;其格式如下 ```swift= // 每次循環都會回頭判斷 condition // 若 condition 為 false 則結束循環,反知繼續循環 while condition { // other code } ``` * `while` 使用範例 ```swift= var value = 1 while value < 100 { print("Before value: \(value)") value = value * 5 print("After value: \(value)\n") } print("Final value: \(value)") ``` > ![](https://i.imgur.com/V3EzKjs.png) * `repeat-while` 與 `while` 差不多,但是 `repeat-while` 的判斷放置到執行程式之後;其格式如下 ```swift= var value = 1 var updating = true repeat { if value < 100 { print("Before value: \(value)") value = value * 5 print("After value: \(value)\n") } else { updating = false } } while updating print("Final value: \(value)") ``` :::warning * `while`, `repeat-while` 使用起來要特別注意,若是沒有修改條件(condition)則會造成無限迴圈 ::: ## 其他 ### 型態別名 - typealias * 首先,型態別名(type alias)只會對該型態取一個別名,並不會修改該型態的特性,**它可以加強程式的可讀性!** 其格式如下 ```swift= typealias <別名> = <型態> ``` * 範例: ```swift= typealias Celsuis = Int typealias Fahrenheit = Int var tempC : Celsuis = 35 var tempF : Fahrenheit tempF = (tempC * 9 / 5) + 32 print("Celsuis = \(tempC), Fahrenheit = \(tempF)") ``` > ![](https://i.imgur.com/HtD3BQj.png) :::warning * 過多的別名可能會導致程式的可讀性降低,最好是將別名限制在某個區域範圍內使用 ::: ### 範疇運算子 * Swift 有提供幾個運算子(符號)來幫助我們簡單定義一組範圍;見下表 | 名稱 | 運算子(符號格式) | 重點 | | - | - | - | | 封閉範疇運算子 | num_1...num_2 | 預設 `<=` (左開又開) | | 半開放範圍運算子 | num_1..<num_2 | 指定 `<` (左開右閉) | | 單邊範圍運算子 | num_1... | 從 >= num_1 開始不限定最大 | | 單邊範圍運算子 | ...num_2 | 不限最最小直到 <= num_2 | ```swift= let hasLess = 10... print("hasLess, contains 10: \(hasLess.contains(10))") print("hasLess, contains 11: \(hasLess.contains(11))") let hasMax = ...100 print("hasMax, contains 100: \(hasMax.contains(100))") print("hasMax, contains 101: \(hasMax.contains(101))") for i in 3...5 { print("hasRange, item: \(i)") } let range = 10..<20 print("range, contains 19: \(range.contains(19))") print("range, contains 20: \(range.contains(20))") ``` > ![](https://i.imgur.com/PXZNrCN.png) * 範疇運算子也可以用在 switch 陳述式中 ```swift= let value = 19 switch value { case 0...10: print("In range 0...10") case 10...20: print("In range 10...20") default: print("Value in other range.") } ``` > ![](https://i.imgur.com/Om9xTTH.png) ## Appendix & FAQ :::info ::: ###### tags: `iOS`