Swift 語言入門(四)標準函式 by Appletone | CodeData
top

Swift 語言入門(四)標準函式

分享:

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?

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,讓它判斷MyStructname相同時,代表相等。

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 繼承兩個協定 _ComparableEquatable,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
  • Algorithms

Printing

印出訊息的主要函式

  • print<T>(_:)
  • println<T>(_:)
  • println()

在 Swift 裡面,有兩個主要印出數值的函式,print()println()println()函式可給值,也可以不用給,沒有給值時就直接印出新的一行。

它們都稱作 free functions,因為他們不用依賴一個接收物件(receiver),可以直接呼叫使用。

print<T>(_:)

將物件文字化,在標準輸出(Standard Output)印出。

宣告

func print<T>(object: T)

使用

要印出的物件,必須遵循 PrintableDebugPrintable協定,如先前介紹,需將物件文字化。

print("Hello, world")
// 印出 "Hello, world"

println<T>(_:)

將物件文字化,在標準輸出(Standard Output)印出,並加上斷行。

宣告

func println<T>(object: T)

使用

要印出的物件,必須遵循 PrintableDebugPrintable協定,如先前介紹,需將物件文字化。

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]

分享:
按讚!加入 CodeData Facebook 粉絲群

留言

留言請先。還沒帳號註冊也可以使用FacebookGoogle+登錄留言

熱門論壇文章

熱門技術文章