Swift 語言入門(三)控制流程 << 前情
今天介紹 Swift 常用的函式,這類的資料不多,大多由開發者從 Xcode 的自動完成去發掘,網路上有人整理出來 74個官方有寫出來跟沒寫出來的標準函式
我們今天來介紹一些常用的型態,以及這些型態有哪些函式可以使用。
文章會介紹 String, Array, Dictionary 函式使用,Numeric Types(Boolean, Integer, Float),Protocols (Equatable, Comparable, Printable) 以及一些內建的演算法函式,並且稍微帶一下 Optional, Enum, Generic 等觀念。
型態
- String
- Array
- Dictionary
- Numeric Types
String
字串(String)是由一連串的字元(Characters)所組成,我們來看看字串、字元有哪些函式可以運用。
建立字串
- init()
- init(count:, repeatedValue:)
init()
初始化一個空的字串。
宣告
init()
使用
let emptyString = String()
let emptyString2 = ""
// 這兩個宣告方式的結果是一樣的,都會產生空的字串。
init(count:, repeatedValue:)
建構一個字串,第一個傳入的參數為重複次數 ,第二個為重複的字元。
宣告
init(count sz: Int, repeatedValue c: Character)
使用
let string = String(count: 5, repeatedValue: Character("a"))
// 上面的程式告訴我們將字元a 重複5次,所以 string 的內容會是 "aaaaa"
字串搜尋
- var isEmpty { get }
- hasPrefix(_ -> Bool
- hasSuffix(_ -> Bool
var isEmpty { get }
isEmpty 用來測試字串是否為空值,get 表示 唯讀(read-only),所以此函式只能取值(get)無法寫入(set)。
宣告
var isEmpty: Bool { get }
使用
var string = "Hello, world!"
let firstCheck = string.isEmpty
// firstCheck is false,因為 string 不為空
string = ""
let secondCheck = string.isEmpty
// secondCheck is true,因為 string 為空字串
hasPrefix(_ -> Bool
hasPrefix 是 String 的函式,用來判斷字串的開頭是否與接收物件(receiver)相同。
宣告
hasPrefix(_ -> Bool
使用
let string = "Hello, world"
let firstCheck = string.hasPrefix("Hello")
// firstCheck is true,因為 string 開頭為 Hello
let secondCheck = string.hasPrefix("hello")
// secondCheck is false,因為 string 開頭為 Hello,hasPrefix 給的值是小寫開頭的 hello,所以視為不同字串!
hasSuffix(_ -> Bool
hasSuffix 與 hasPrefix 類似,字面上的意思則是字尾是否相同。
宣告
func hasSuffix(suffix: String) -> Bool
使用
let string = "Hello, world"
let firstCheck = string.hasSuffix("world")
// firstCheck is true,因為 string 結尾為 world
let secondCheck = string.hasSuffix("World")
// secondCheck is false,因為 string 結尾為 world,hasSuffix 給的值是大寫開頭的 World,所以是為不同字串!
字串轉型
toInt() -> Int?
將字串轉為 Int 型態,但回傳的結果是 Optional Integer。
Optional 是一個 Enum ,定義兩種型態 None & Some(T) ,None 代表空值,Some帶著某種任意的型態,保存著應該呈現的數值,例如本次範例所要表達的 Int? ,如果回傳的結果是正確的,Some就會帶著 Int 回傳結果。
Enum 中文叫做 列舉,是 Enumerations 的縮寫,在程式當中用來定義一組相關的數值,例如:方位,可定義出 東、南、西、北,Optional 則 定義 None、Some。Enum 在 Swift 語言當中有許多強化的功能,後續的章節我們再來介紹。
宣告
func toInt() -> Int?
使用
let string = "42"
if ( let number = string.toInt() ) {
println("字串轉為數字: \(number)")
}
else {
println("無法轉換!")
}
// prints "字串轉為數字: 42"
運算元
以前在 Objective-C 字串的串接不是那麼的方便與直覺,Swift 有了字串運算元的加持,我們可以用更直覺的方式,來做字串相加。
+
字串串接,在這裡必須先跟大家說明 Swift 的演進,以前是可以透過加號運算元(+)串接字元,自從 Xcode6 beta6 就不再允許這樣做,Characters 與 Strings 相加必須改用 String(c1) ,字元必須做一個轉型的動作。
宣告
func + (lhs: String, rhs: String) -> String
func + (lhs: Character, rhs: Character) -> String
// 底下為舊版本,將不再支援!
func + (lhs: String, rhs: Character) -> String
func + (lhs: Character, rhs: String) -> String
使用
let combination = "Hello " + "world"
// 字串相加後的結果 is "Hello world"
字元與字串相加必須轉為字串!
let exclamationPoint: Character = "!"
let charCombo = combination + String(exclamationPoint)
// charCombo is "Hello world!"
let extremeCombo = String(exclamationPoint) + charCombo
// extremeCombo is "!Hello world!"
字元相加後會轉為字串
let first: Character = "a"
let second: Character = "b"
let result = first + second
// result 會轉成字串 內容為 "ab"
+=
字串的附加運算元。
宣告
@assignment func += (inout lhs: String, rhs: String)
// 已經被移除的函式
@assignment func += (inout lhs: String, rhs: Character)
使用
var string = "Hello "
string += "world!"
// string is "Hello world!"
字元必須轉型字串方能與字串相加。
var character: Character = "?"
string += String(character)
// string is "Hello world!?"
常數無法附加字串。所以此處 let string 要改為 var string。
let string = "Hello "
string += "world!"
// 錯誤: 常數無法附加字串!
==
判斷字串內容是否相等。
宣告
func == (lhs: String, rhs: String) -> Bool
使用
let string1 = "Hello world!"
let string2 = "Hello" + " " + "world" + "!"
let result = string1 == string2
// 結果會是 true
<
字串的比較運算,比較運算元會把字串轉換成可以比較的數字,使字串與字串、字元與字元可相互比較。
宣告
func < (lhs: String.UnicodeScalarView.Index, rhs: String.UnicodeScalarView.Index) -> Bool
func < (lhs: Character, rhs: Character) -> Bool
使用
字串與字串比較。
let string1 = "Number 3"
let string2 = "Number 2"
let result1 = string1 < string2
// 結果會是 false
let result2 = string2 < string1
// 結果會是 true
字串與字串比較。
let string3 = "aa"
let string4 = "bb"
string3 < string4
// 結果會是 true
string4 < string3
// 結果會是 false
字元與字元比較。
let c1 = "a"
let c2 = "b"
c1 < c2
// 結果會是 true
c2 < c1
// 結果會是 false
Array
- 建立陣列
- 存取陣列元素
- 增加、移除陣列元素
- 陣列搜尋
- 陣列的演算法
- 運算元
陣列是一個儲存連續資料的型態,他們必須存放相同型態(T)的元素。
<T> 此處稱作泛型(Generic),此處的泛型用來定義陣列裡的元素必須相同,其實泛型的另個用途在於程式碼靈活地重複使用。例如:我們定義一個型態為 Stack<T>,就不需要 Int 也寫一個 IntStack,String 也寫一個 StringStack,運用泛型就可重複利用程式碼。
建立陣列
- init()
- init(count:, repeatedValue:)
init()
創建一個空陣列。
宣告
init()
使用
var emptyArray = Array<Int>()
var equivalentEmptyArray = [Int]()
// 這兩句程式的結果是一樣的,將型態擺在 <> or [] 中間。
init(count:, repeatedValue:)
創建一個陣列相同元素內容的陣列,第一個參數代表 重複的數量,第二個參數代表元素的數值,
宣告
init(count: Int, repeatedValue: T)
使用
let numericArray = Array(count: 3, repeatedValue: 42)
// numericArray 結果會是 [42, 42, 42]
let stringArray = Array(count: 2, repeatedValue: "Hello")
// stringArray 結果會是 ["Hello", "Hello"]
存取陣列元素
- subscript(Int) -> T { get set }
- subscript(Range) -> Slice
subscript 叫做下標語法,接收物件(receiver) 可以用中括號呼叫函式。
subscript(Int) -> T { get set }
透過中括號與Index( Array[index] ),可取得陣列的特定元素。
宣告
subscript(index: Int) -> T { get { } nonmutating set { } }
使用
var subscriptableArray = ["zero", "one", "two", "three"] subscriptableArray[0]
// 取得 "zero"
let three = subscriptableArray[3]
// 取得 "three"
如果陣列宣告為 var,我們將可變動其內部的數值。
所以陣列的下標語法,不僅可以 get 也能 set。
subscriptableArray[0] = "nothing"
subscriptableArray[3] = "three items"
注意陣列範圍。
subscriptableArray[4] = "new item"
// 錯誤: 超出陣列範圍!
注意常數陣列無法更動。
let constantArray = ["zero", "one", "two", "three"] constantArray[0] = "nothing"
// 錯誤: 無法變動常數陣列
subscript(Range) -> Slice
使用中括號下標語法傳入 Range 並且為 Int 型態,將符合的元素回傳為 Slice 。
宣告
subscript(subRange: Range<Int>) -> Slice<T> { get { } set { } }
使用
取得 1到3 包含3的元素,陣列元素從 0 開始算起 ,所以結果是:["one", "two", "three"]。
var subscriptableArray = ["zero", "one", "two", "three"]
let subRange = subscriptableArray[1...3]
// 結果為 ["one", "two", "three"]
將 1到2 元素,取代為 ["oneone", "twotwo"] 此二元素。
subscriptableArray[1...2] = ["oneone", "twotwo"]
// 結果為 ["zero", "oneone", "twotwo", "three"]
將 1到2 元素,取代為 空陣列。
subscriptableArray[1...2] = []
// subscriptableArray 內容剩下 ["zero", "three"]
注意陣列範圍。
subscriptableArray[4...5] = ["four", "five"]
// 錯誤: 陣列取代超過範圍
注意陣列是否為常數。
let constantArray = ["zero", "one", "two", "three"] constantArray[1...2] = []
// 錯誤: 無法更動常數陣列
增加、移除陣列元素
- append()
- insert(_ :, atIndex:)
- removeAtIndex() -> T
- removeLast() -> T
- removeAll(keepCapacity: = false)
- reserveCapacity()
append()
附加一個元素到一個已經存在的陣列。
宣告
mutating func append(newElement: T)
使用
var array = [0, 1]
array.append(2)
// array 的結果為 [0, 1, 2]
array.append(3)
// array 的結果為 [0, 1, 2, 3]
相同的,您無法附加一個元素,到一個常數陣列。
let constantArray = [0, 1]
constantArray.append(2)
// 錯誤: immutable value of type '[Int]' only has mutating members named 'append'
insert(_ :, atIndex:)
插入一個元素,到陣列的特定位置。注意插入不是取代!
宣告
mutating func insert(newElement: T, atIndex: Int)
使用
在陣列的最前面插入 0。
var array = [1, 2, 3]
array.insert(0, atIndex: 0)
// array 的結果為 [0, 1, 2, 3]
同樣的,不能超出陣列範圍。
array.insert(6, atIndex: 6)
// 錯誤: Array replace: subRange extends past the end
一樣無法針對常數陣列做插入的動作。
let constantArray = [1, 2, 3]
constantArray.insert(0, atIndex: 0)
// 錯誤: immutable value of type '[Int]' only has mutating members named 'insert'
removeAtIndex() -> T
移除特定元素。
宣告
mutating func removeAtIndex(index: Int) -> T
使用
移除陣列的第一個元素。
var array = [0, 1, 2, 3]
let removed = array.removeAtIndex(0)
// array 結果為 [1, 2, 3]
// 0 被移除
同樣不可超出陣列範圍。
array.removeAtIndex(5)
// 錯誤: Array index out of range
常數陣列不可變動。
let constantArray = [0, 1, 2] constantArray.removeAtIndex(0)
// 錯誤: immutable value of type '[Int]' only has mutating members named
'removeAtIndex'
removeLast() -> T
移除陣列最後一個元素,並且回傳它。
宣告
mutating func removeLast() -> T
使用
var array = [1, 2, 3]
let removed = array.removeLast()
// array 的內容變為 [1, 2]
// removed 內容為 3
呼叫 removeLast 函式,陣列內必須至少有一個元素在裡面,否則將會出錯。
var emptyArray = [Int]()
let tryToRemove = emptyArray.removeLast()
// 錯誤: can't removeLast from an empty Array
常數陣列不可修改。
let constantArray = [1, 2]
constantArray.removeLast()
// 錯誤: immutable value of type '[Int]' only has mutating members named 'removeLast'
removeAll(keepCapacity: = false)
移除陣列所有元素,預設為清空 storage buffer,除非特別指定keepCapacity。
宣告
mutating func removeAll(keepCapacity: Bool = false)
使用
var array = [0, 1, 2, 3]
array.removeAll()
let count = array.count
// count 為 0
常數陣列無法更動。
let constantArray = [1, 2]
constantArray.removeAll()
// 錯誤: immutable value of type '[Int]' only has mutating members named 'removeAll'
reserveCapacity()
設定陣列底層的儲存空間。
Array 在記憶體所展示的是一段連續記憶體空間,如果元素超過了此設定大小的空間,則必須重新配置空間來存放元素。
宣告
mutating func reserveCapacity(minimumCapacity: Int)
使用
var array = [0, 1, 2, 3]
array.reserveCapacity(10)
// 將陣列空間設定到 10
陣列搜尋
- var count { get }
- var isEmpty { get }
- var capacity { get }
var count { get }
回傳總共有幾個元素。
宣告
var count: Int { get }
使用
var array = ["zero", "one", "two"]
let firstCount = array.count
// 元素共 3 個
array += "three"
let secondCount = array.count
// 元素共 4 個
var isEmpty { get }
isEmpty 用來測試陣列是否為空陣列,get 表示 唯讀(read-only),所以此函式只能取值(get)無法寫入(set)。
宣告
var isEmpty: Bool { get }
使用
var array = ["zero", "one", "two", "three"]
let firstCheck = array.isEmpty
// firstCheck 為 false
array.removeAll()
let secondCheck = array.isEmpty
// secondCheck 為 true
var capacity { get }
顯示目前陣列所配置的空間大小為多少,get 表示 唯讀(read-only)。
宣告
var capacity: Int { get }
使用
var array = [0, 1, 2, 3]
array.capacity
// array 的 capacity 為 4
陣列的演算法
- sort(_
- sorted(_ -> Array<T>
- reverse() -> Array<T>
- filter(_ -> Array<T>
- map<U>(_ -> Array<U>
- reduce<U>(_:, combine: (U, T)->U) -> U
sort(_
Swift 內建一些常用的演算法,像是 sort,我們可以透過 Closure 去比對,並且排序。
Closure 像是 Objective-C 裡頭的 Block 概念或稱之為 lambda 函式。Closure 在 Swift 語言裡頭也是扮演很重要的角色。之後的教學文章將會特別說明。
宣告
mutating func sort(isOrderedBefore: (T, T) -> Bool)
使用
sort 函式只有一個參數,但這個參數比較特別,它是 Closure ,在Closure 內執行的結果必須回傳 Bool 值,isOrderedBefore 表示如果回傳為 true,將排在前面,反之往後排序。
此範例出現神奇的變數,$0, $1,稱作 Shorthand Argument Names ,這個意思是參數名稱縮寫,從 $0 開始代表第一個參數,$1 第二個,依此類推。
在此 sort 函式的用法應該為 array.sort( { $0 < $1 } ) ,括號為呼叫函式,括號內為 Closure 參數,但此處使用的方式叫做 Trailing Closures ,若 Closure 為函式最後一個參數時,可提出括號外面撰寫部分程式,若只有一個 Closure 參數時,甚至不需要括號,如下範例,可讓程式碼更簡潔易讀。
var array = [3, 2, 5, 1, 4]
array.sort { $0 < $1 }
// array 升冪排序 [1, 2, 3, 4, 5]
array.sort { $1 < $0 } // 或 array.sort { $0 > $1 }
// array 降冪排序 [5, 4, 3, 2, 1]
sorted(_ -> Array<T>
跟 sort 函式類似,不過 sorted 會將排序結果,組成陣列回傳。
宣告
func sorted(isOrderedBefore: (T, T) -> Bool) -> Array<T>
使用
let array = [3, 2, 5, 1, 4]
let sortedArray = array.sorted { $0 < $1 }
// sortedArray 升冪排序 [1, 2, 3, 4, 5]
let descendingArray = array.sorted { $1 < $0 }
// descendingArray 降冪排序 [5, 4, 3, 2, 1]
reverse() -> Array<T>
回傳一個反向的陣列。
宣告
func reverse() -> Array<T>
使用
let array = [2, 0, 1, 4]
let reversedArray = array.reverse()
// reversedArray = [4, 1, 0, 2]
filter(_ -> Array<T>
尋訪每個陣列內的元素,執行傳入的 Closure 回傳 ture 時,加入回傳結果的陣列。
宣告
func filter(includeElement: (T) -> Bool) -> Array<T>
使用
尋訪每個元素,留下二的倍數。
let array = [0, 1, 2, 3, 4, 5, 6, 7]
let filteredArray = array.filter { $0 % 2 == 0 }
// filteredArray 內容是 [0, 2, 4, 6]
map<U>(_ -> Array<U>
尋訪每個元素,執行傳入的 Closure 加以處理元素後,加入回傳的陣列當中。
宣告
func map<U>(transform: (T) -> U) -> Array<U>
使用
map 可將每個 陣列的元素加以處理,將每個元素乘上倍數,或將元素組成字串。
let array = [0, 1, 2, 3]
let multipliedArray = array.map { $0 * 2 }
// 將array每個元素乘上2,multipliedArray 內容變為 [0, 2, 4, 6]
let describedArray = array.map { "Number: \($0)" }
// 將array每個元素組成字串,describedArray 內容變為 [Number: 0, Number: 1, Number: 2, Number: 3]
reduce<U>(_:, combine: (U, T)->U) -> U
尋訪每個元素,並將該尋訪的元素,成為下個元素的處理參數,又稱之為 fold 。
宣告
func reduce<U>(initial: U, combine: (U, T) -> U) -> U
使用
reduce 的用法,需給它一個初始值,接著在尋訪每個元素時,與每個元素計算結合為一個元素,以遞迴的方式,不斷的呼叫第二個參數,Closure 運算。
舉個例子:從 1 加到 5。
let array = [1, 2, 3, 4, 5]
let addResult = array.reduce(0) { $0 + $1 }
// reduce array 初始值 0,不斷的相加,並把結果丟給下個元素,所以addResult 結果是 15
let multiplyResult = array.reduce(1) { $0 * $1 }
// reduce array 初始值 1,不斷的相乘,所以 multiplyResult 結果為 120
第一個 array 相加 的 reduce,將它拆解後,初始值我們給0,所以第一步將是 初始值 0 + array第一個元素 1 ,相加結果是 1,第二部是將 第一步算得的結果 1 + array第二個元素 2 ,以此類推。
相乘的例子也是一樣,初始值我們給1,所以第一步將是 初始值 1 * array第一個元素 1 ,相乘結果是 1,第二部是將 第一步算得的結果 1 * array第二個元素 2 ,以此類推。
陣列運算元
+=
陣列的附加,原本在 Xcode6 beta5 之前,可以任意附加元素或是陣列,但之後修改為,必須要是陣列與陣列才能附加。如同宣告方式所定義:
宣告
func +=<T, C : CollectionType where T == T>(inout lhs: _ContiguousArrayBuffer<T>, rhs: C)
// 舊的做法
@assignment func += <U>(inout lhs: Array<T>, rhs: U)
使用
此處用法注意 += 兩端皆需為陣列型態。
var array = [0, 1, 2]
array += [3]
// array 結果為 [0, 1, 2, 3]
array += [4, 5, 6]
// array 結果為 [0, 1, 2, 3, 4, 5, 6]
Dictionary
- 建立字典
- 存取、修改字典內容
- 字典搜尋
- 字典的運算元
字典也是個必須遵守泛型(Generic)的一種形態,顧名思義類似字典,儲存著鍵值(key)與數值(value),例如:apple 對應到 蘋果,假設 apple 為鍵值,對應到的數值結果就是 蘋果。
建立字典
- init(minimumCapacity: = 2)
init(minimumCapacity: = 2)
創建字典,最小記憶體空間預設值為2。
宣告
init(minimumCapacity: Int = 2)
使用
var emptyDictionary = Dictionary<String, Int>()
// 建立一個空的字典,鍵值形態為String,數值形態為Int。
這兩種宣告方式的結果是一樣的。
var equivalentEmptyDictionary = [String: Int]()
存取、修改字典內容
- subscript (key: Key) -> Value?
- updateValue(_:, forKey:) -> Value?
- removeValueForKey(_:) -> Value?
- removeAll(keepCapacity: = false)
subscript (key: Key) -> Value?
下標語法subscript 在陣列與字典都很常用,而且直覺,許多語言大多都是以這樣的方式存取。
宣告
subscript (key: Key) -> Value?
使用
var dictionary = ["one": 1, "two": 2, "three": 3]
let value = dictionary["two"]
// 所以回傳的 value 會是一個 optional 帶著 2 這個數值。
這邊用到的是一種 Optional 特殊寫法,叫做 Optional Binding ,訣竅是 if let ,若 Optional 有值 會直接賦予到變數當中,若沒有值,則為 false 條件不成立。這樣我們就不用猜測變數究竟會是什麼型態,而寫出許多判斷式,我們稱之為防禦性編程(Defensive Programming),減少這類的程式碼,問題與臭蟲相對較少,開發者也能更專注在資料流與商業邏輯。
if let unwrappedValue = dictionary["three"] {
println("字典透過鍵值 \"three\" 取出的值是 \(unwrappedValue)")
}
// prints "字典透過鍵值 "three" 取出的值是 3"
能用下標語法取值,同樣也能用來更新數值。
dictionary["three"] = 33
// dictionary 更新為 ["one": 1, "two": 2, "three": 33]
dictionary["four"] = 4
// dictionary 多個 key-value ["one": 1, "two": 2, "three": 33, "four": 4]
dictionary["three"] = nil
// dictionary three 被移除 ["one": 1, "two": 2, "four": 4]
若字典定義為常數,修改的下標語法將無法使用!
let constantDictionary = ["one": 1, "two": 2, "three": 3]
constantDictionary["four"] = 4
// 錯誤: could not find an overload for 'subscript' that accepts the supplied
arguments
updateValue(_:, forKey:) -> Value?
插入或更新字典數值,第一個參數為更新的數值,第二個參數為鍵值,並回傳將被取代的數值。
宣告
mutating func updateValue(value: Value, forKey key: Key) -> Value?
使用
var dictionary = ["one": 1, "two": 2, "three": 3]
let previousValue = dictionary.updateValue(22, forKey: "two")
// previousValue 將會是個 Optional 型態,帶著 2 這個數值。
若用 Optional Binding 方式表達,則範例如下:
if let unwrappedPreviousValue = dictionary.updateValue(33, forKey: "three") {
println("取代的數值為 \(unwrappedPreviousValue)")
}
else {
println("這是一個新的 key-value ")
}
// prints "取代的數值為 3"
removeValueForKey(_:) -> Value?
傳入鍵值,移除該組 key-value,並且回傳被移除的數值。
宣告
mutating func removeValueForKey(key: Key) -> Value?
使用
var dictionary = ["one": 1, "two": 2, "three": 3]
let previousValue = dictionary.removeValueForKey("two")
// previousValue 將會是個 Optional 型態,帶著 2 這個數值。
removeValueForKey 將回傳被移除的數值。
if let unwrappedPreviousValue = dictionary.removeValueForKey("three") {
println("移除的數值為 \(unwrappedPreviousValue)")
}
else {
println("找不到可以刪除的值")
}
// prints "移除的數值為 3"
removeAll(keepCapacity: = false)
移除字典內所有 key-value 數值,預設為清空 storage buffer,除非特別指定keepCapacity。
宣告
mutating func removeAll(keepCapacity: Bool = default)
使用
var dictionary = ["one": 1, "two": 2, "three": 3] dictionary.removeAll()
// dictionary 被清空了
字典搜尋
- var count { get }
- var keys { get }
- var values { get }
var count { get }
將回傳 字典共有多少組 key-value。
宣告
var count: Int { get }
使用
var dictionary = ["one": 1, "two": 2, "three": 3]
let elementCount = dictionary.count
// elementCount 等於 3
var keys { get }
這是個唯讀的函式,回傳所有鍵值,並且為 CollectionType。
宣告
var keys: LazyBidirectionalCollection<MapCollectionView<[Key : Value], Key>> { get }
使用
使用 for-in 迴圈尋訪每個鍵值,並且印出來。
var dictionary = ["one": 1, "two": 2, "three": 3]
for key in dictionary.keys {
println(key)
}
// 結果印出:
// one
// two
// three
轉為 Array 即可使用 Array 的函式。
let array = Array(dictionary.keys)
// array is ["one", "two", "three"]
var values { get }
回傳字典內所有數值,這是個未排序的數值 collection。
宣告
var values: LazyBidirectionalCollection<MapCollectionView<[Key : Value], Value>> { get }
使用
var dictionary = ["one": 1, "two": 2, "three": 3]
for value in dictionary.values {
println("數值: \(value)")
}
// 結果印出:
// 數值: 1
// 數值: 2
// 數值: 3
轉為 Array 即可使用 Array 的函式。
let array = Array(dictionary.values)
// array is [1, 2, 3]
字典的運算元
==
判斷字典內容是否相等。
宣告
func ==<Key : Equatable, Value : Equatable>(lhs: [Key : Value], rhs: [Key : Value]) -> Bool
使用
定義一個 dictionary1 的字典常數,然後跟一個 dictionary2 的字典比較,內容相同為 true。
let dictionary1 = ["one": 1, "two": 2]
var dictionary2 = ["one": 1]
dictionary2["two"] = 2
let result = dictionary1 == dictionary2
// 結果為 true
!=
用法與== 相同,只不過意思相反,用來比較字典內容是否不相同。
宣告
func !=<Key : Equatable, Value : Equatable>(lhs: [Key : Value], rhs: [Key : Value]) -> Bool
使用
因為 dictionary1 與 dictionary2 內容完全不同,所以結果為 true。
let dictionary1 = ["one": 1, "two": 2]
let dictionary2 = ["one": 1]
let result = dictionary1 != dictionary2
// 結果為 true
Numeric Types
- Boolean Types
- Integer Types
- Floating Point Types
Swift 標準函式使用數值型態來表示與儲存布林值、數字、浮點數。
Boolean Types
Swift 的布林型態叫做 Bool,分別只有兩種內容 true 與 false,預設為 false。
Integer Types
Swift 的主要數字型態 Int 在 32bit 的平台,它的大小就會是 32bit,在64bit的平台就會是64bit。
下表為 Int 數值的範圍:
型別 |
最小值 |
3最大值 |
Int8 |
-128 |
127 |
Int16 |
-32,768 |
32,767 |
Int32 |
-2,147,483,648 |
2,147,483,647 |
Int64 |
-9,223,372,036,854,775,808 |
9,223,372,036,854,775,807 |
UInt8 |
0 |
255 |
UInt16 |
0 |
65,535 |
UInt32 |
0 |
4,294,967,295 |
UInt64 |
0 |
18,446,744,073,709,551,615 |
Floating Point Types
在 Swift 主要的浮點數型態為 Double,使用的是 64bit的精準度,當然也可以使用32bit精準度的 Float。
Protocols
- Equatable
- Comparable
- Printable
我們將介紹 Swift 語言裡面,最基礎常見的三個Protocols (協定)。
Equatable
判斷是否相等
==
宣告
func == (lhs: Self, rhs: Self) -> Bool
使用
底下定義一個 struct 叫 MyStruct,遵從 Equatable 協定,我們必須在全域環境底下實作 == function,並且回傳布林值 true 代表相等,false 則不相等。
我們實作== function,讓它判斷MyStruct 的name 相同時,代表相等。
struct MyStruct: Equatable {
var name = "不具名"
}
func == (lhs: MyStruct, rhs: MyStruct) -> Bool {
return lhs.name == rhs.name
}
let value1 = MyStruct()
var value2 = MyStruct()
let firstCheck = value1 == value2
// 因為兩個初始name都是一樣的,所以第一次比較結果為相等
value2.name = "路人甲"
let secondCheck = value1 == value2
// 把 value2 的名字改掉後比較 value1,結果為不相等
Comparable
比較值
<
Comparable 協定 讓兩個值可以比較大或小。
而最少必須實作< 與== ,為什麼?我們來看原始碼。
Comparable 繼承兩個協定 _Comparable 、Equatable ,Equatable剛剛說明過了,我們來看另外一個 _Comparable,是的就是< ,當實作完< 與== ,您將自動獲得 <= 、>= 、> 這三個比較運算元!
宣告
protocol Comparable : _Comparable, Equatable {
func <=(lhs: Self, rhs: Self) -> Bool
func >=(lhs: Self, rhs: Self) -> Bool
func >(lhs: Self, rhs: Self) -> Bool
}
protocol _Comparable {
func <(lhs: Self, rhs: Self) -> Bool
}
使用
struct MyStruct: Comparable {
var name = "A"
}
// 必須實作 _Comparable
func < (lhs: MyStruct, rhs: MyStruct) -> Bool {
return lhs.name < rhs.name
}
// 必須實作 Equatable
func == (lhs: MyStruct, rhs: MyStruct) -> Bool {
return lhs.name == rhs.name
}
let value1 = MyStruct()
var value2 = MyStruct()
let check1 = value1 < value2
// check1 為 false
let check2 = value1 <= value2
// check2 為 true
// value2.name 設為 B
value2.name = "B"
let check3 = value1 >= value2
// check3 為 false
let check4 = value1 > value2
// check4 為 false
Printable
定義印出的內容
description { get }
宣告
protocol Printable {
var description: String { get }
}
使用
struct MyName: Printable {
var name = "路人甲"
var description: String {
return "我的名字是 \(name)"
}
}
let value = MyName()
println(value)
// 印出:我的名字是 路人甲
Free Functions
Printing
印出訊息的主要函式
- print<T>(_:)
- println<T>(_:)
- println()
在 Swift 裡面,有兩個主要印出數值的函式,print() 與println() ,println() 函式可給值,也可以不用給,沒有給值時就直接印出新的一行。
它們都稱作 free functions ,因為他們不用依賴一個接收物件(receiver),可以直接呼叫使用。
print<T>(_:)
將物件文字化,在標準輸出(Standard Output)印出。
宣告
func print<T>(object: T)
使用
要印出的物件,必須遵循 Printable 或 DebugPrintable 協定,如先前介紹,需將物件文字化。
print("Hello, world")
// 印出 "Hello, world"
println<T>(_:)
將物件文字化,在標準輸出(Standard Output)印出,並加上斷行。
宣告
func println<T>(object: T)
使用
要印出的物件,必須遵循 Printable 或 DebugPrintable 協定,如先前介紹,需將物件文字化。
println("Hello, world")
// 印出 "Hello, world" 並斷行
println()
直接在標準輸出,印出斷行。
宣告
func println()
使用
直接呼叫使用。
print("Hello, world")
println()
// 印出 "Hello, world",後面呼叫 println() 斷行。
Algorithms
- sort<T: Comparable>(inout array: T[])
- sort<T>(inout array: T[], pred: (T, T) -> Bool) -> T[]
- sorted<T: Comparable>(array: T[]) -> T[]
- sorted<T>(array: T[], pred: (T, T) -> Bool) -> T[]
Swift 內建了許多常用的演算法,包含 排序、搜尋…等等,所以很多我們不用自己重複造車,就能享用 Swift 帶來方便的函式。
sort<T: Comparable>(inout array: T[])
如同之前所介紹的Comparable 協定,傳入陣列的元素,必須遵循此協定才能比較並排序。
宣告
func sort<T: Comparable>(inout array: T[])
使用
此處宣告的 sort function 傳入的參數陣列前面多了一個inout 關鍵字,這代表的意思是,此處傳入的參數 是可以被修改並替換的。
現在將陣列傳入一個,inout 參數的函式,必須將參數明確表示,在變數前面必須加上& 。
var array = [5, 1, 6, 4, 2, 3]
sort(&array)
// array 排序後,並且被替換為 [1, 2, 3, 4, 5, 6]
常數無法被丟進inout 參數處理。
let constantArray = [5, 1, 6, 4, 2, 3]
sort(&constantArray)
// 錯誤: cannot mutate a constant array
sort<T>(inout array: T[], pred: (T, T) -> Bool) -> T[]
類似之前介紹的 Array.sort,第二個參數 Closure ,在Closure 內執行的結果必須回傳 Bool 值,isOrderedBefore 表示如果回傳為 true,將排在前面,反之往後排序。
宣告
func sort<T>(inout array: [T], isOrderedBefore: (T, T) -> Bool)
使用
var array = [5, 1, 3, 4, 2, 6]
sort(&array) { $0 > $1 }
// array 排序後,並且被替換為 [6, 5, 4, 3, 2, 1]
sorted<T: Comparable>(array: T[]) -> T[]
與sort 類似,sorted 則是回傳結果陣列,不去更動原來的陣列物件。
宣告
func sorted<C : MutableCollectionType where C.Index : RandomAccessIndexType, C.Generator.Element : Comparable>(source: C) -> C
使用
因為不需更動array 物件,所以此處 array 前面不需加& 。
let array = [5, 1, 6, 4, 2, 3]
let result = sorted(array)
// result陣列,排序結果為 [1, 2, 3, 4, 5, 6]
sorted<T>(array: T[], pred: (T, T) -> Bool) -> T[]
類似之前介紹的 sort,第二個參數 Closure ,在Closure 內執行的結果必須回傳 Bool 值,isOrderedBefore 表示如果回傳為 true,將排在前面,反之往後排序。
宣告
func sorted<C : MutableCollectionType where C.Index : RandomAccessIndexType>(source: C, isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool) -> C
使用
let array = [5, 1, 3, 4, 2, 6]
let result = sorted(array) { $0 > $1 }
// result陣列,排序結果為 [6, 5, 4, 3, 2, 1]
|