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

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

tags:  行動開發  函式  iOS  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()

初始化一個空的字串。

宣告

1
init()

使用

1
2
3
4
let emptyString = String()
let emptyString2 = ""
 
// 這兩個宣告方式的結果是一樣的,都會產生空的字串。

init(count:, repeatedValue:)

建構一個字串,第一個傳入的參數為重複次數,第二個為重複的字元。

宣告

1
init(count sz: Int, repeatedValue c: Character)

使用

1
2
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)。

宣告

1
var isEmpty: Bool { get }

使用

1
2
3
4
5
6
7
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)相同。

宣告

1
hasPrefix(_ <img src= "https://i-blog.csdnimg.cn/blog_migrate/2706487732b1b7a6c54591a8fec614d9.gif" alt= ":)" class = "wp-smiley" >  -> Bool

使用

1
2
3
4
5
6
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 類似,字面上的意思則是字尾是否相同。

宣告

1
func hasSuffix(suffix: String) -> Bool

使用

1
2
3
4
5
6
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 語言當中有許多強化的功能,後續的章節我們再來介紹。

宣告

1
func toInt() -> Int?

使用

1
2
3
4
5
6
7
8
let string = "42"
if ( let number = string.toInt() ) {
     println( "字串轉為數字: \(number)" )
}
else {
     println( "無法轉換!" )
}
// prints "字串轉為數字: 42"

運算元

  • +
  • +=
  • ==
  • <

以前在 Objective-C 字串的串接不是那麼的方便與直覺,Swift 有了字串運算元的加持,我們可以用更直覺的方式,來做字串相加。

+

字串串接,在這裡必須先跟大家說明 Swift 的演進,以前是可以透過加號運算元(+)串接字元,自從 Xcode6 beta6 就不再允許這樣做,Characters 與 Strings 相加必須改用 String(c1),字元必須做一個轉型的動作。

宣告

1
2
3
4
5
6
func + (lhs: String, rhs: String) -> String
func + (lhs: Character, rhs: Character) -> String
 
// 底下為舊版本,將不再支援!
func + (lhs: String, rhs: Character) -> String
func + (lhs: Character, rhs: String) -> String

使用

1
2
let combination = "Hello " + "world"
// 字串相加後的結果 is "Hello world"

字元與字串相加必須轉為字串!

1
2
3
4
5
6
let exclamationPoint: Character = "!"
let charCombo = combination + String(exclamationPoint)
// charCombo is "Hello world!"
 
let extremeCombo = String(exclamationPoint) + charCombo
// extremeCombo is "!Hello world!"

字元相加後會轉為字串

1
2
3
4
let first: Character = "a"
let second: Character = "b"
let result = first + second
// result 會轉成字串 內容為 "ab"

+=

字串的附加運算元。

宣告

1
2
3
4
@assignment func += (inout lhs: String, rhs: String)
 
// 已經被移除的函式
@assignment func += (inout lhs: String, rhs: Character)

使用

1
2
3
var string = "Hello "
string += "world!"
// string is "Hello world!"

字元必須轉型字串方能與字串相加。

1
2
3
var character: Character = "?"
string += String(character)
// string is "Hello world!?"

常數無法附加字串。所以此處 let string 要改為 var string。

1
2
3
let string = "Hello "
string += "world!"
// 錯誤: 常數無法附加字串!

==

判斷字串內容是否相等。

宣告

1
func == (lhs: String, rhs: String) -> Bool

使用

1
2
3
4
let string1 = "Hello world!"
let string2 = "Hello" + " " + "world" + "!"
let result = string1 == string2
// 結果會是 true

<

字串的比較運算,比較運算元會把字串轉換成可以比較的數字,使字串與字串、字元與字元可相互比較。

宣告

1
2
func < (lhs: String.UnicodeScalarView.Index, rhs: String.UnicodeScalarView.Index) -> Bool
func < (lhs: Character, rhs: Character) -> Bool

使用

字串與字串比較。

1
2
3
4
5
6
7
8
let string1 = "Number 3"
let string2 = "Number 2"
 
let result1 = string1 < string2
// 結果會是 false
 
let result2 = string2 < string1
// 結果會是 true

字串與字串比較。

1
2
3
4
5
6
7
let string3 = "aa"
let string4 = "bb"
 
string3 < string4
// 結果會是 true
string4 < string3
// 結果會是 false

字元與字元比較。

1
2
3
4
5
6
7
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()

創建一個空陣列。

宣告

1
init()

使用

1
2
3
4
var emptyArray = Array<Int>()
var equivalentEmptyArray = [Int]()
 
// 這兩句程式的結果是一樣的,將型態擺在 <> or [] 中間。

init(count:, repeatedValue:)

創建一個陣列相同元素內容的陣列,第一個參數代表 重複的數量,第二個參數代表元素的數值,

宣告

1
init(count: Int, repeatedValue: T)

使用

1
2
3
4
5
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] ),可取得陣列的特定元素。

宣告

1
subscript(index: Int) -> T { get { } nonmutating set { } }

使用

1
2
3
4
5
var subscriptableArray = [ "zero" , "one" , "two" , "three" ] subscriptableArray[ 0 ]
// 取得 "zero"
 
let three = subscriptableArray[ 3 ]
// 取得 "three"

如果陣列宣告為 var,我們將可變動其內部的數值。
所以陣列的下標語法,不僅可以 get 也能 set。

1
2
subscriptableArray[ 0 ] = "nothing"
subscriptableArray[ 3 ] = "three items"

注意陣列範圍。

1
2
subscriptableArray[ 4 ] = "new item"
// 錯誤: 超出陣列範圍!

注意常數陣列無法更動。

1
2
let constantArray = [ "zero" , "one" , "two" , "three" ] constantArray[ 0 ] = "nothing"
// 錯誤: 無法變動常數陣列

subscript(Range) -> Slice

使用中括號下標語法傳入 Range 並且為 Int 型態,將符合的元素回傳為 Slice

宣告

1
subscript(subRange: Range<Int>) -> Slice<T> { get { } set { } }

使用

取得 1到3 包含3的元素,陣列元素從 0 開始算起,所以結果是:["one", "two", "three"]。

1
2
3
var subscriptableArray = [ "zero" , "one" , "two" , "three" ]
let subRange = subscriptableArray[ 1 ... 3 ]
// 結果為 ["one", "two", "three"]

將 1到2 元素,取代為 ["oneone", "twotwo"] 此二元素。

1
2
subscriptableArray[ 1 ... 2 ] = [ "oneone" , "twotwo" ]
// 結果為 ["zero", "oneone", "twotwo", "three"]

將 1到2 元素,取代為 空陣列。

1
2
subscriptableArray[ 1 ... 2 ] = []
// subscriptableArray 內容剩下 ["zero", "three"]

注意陣列範圍。

1
2
subscriptableArray[ 4 ... 5 ] = [ "four" , "five" ]
// 錯誤: 陣列取代超過範圍

注意陣列是否為常數。

1
2
let constantArray = [ "zero" , "one" , "two" , "three" ] constantArray[ 1 ... 2 ] = []
// 錯誤: 無法更動常數陣列

增加、移除陣列元素

  • append()
  • insert(_ :, atIndex:)
  • removeAtIndex() -> T
  • removeLast() -> T
  • removeAll(keepCapacity: = false)
  • reserveCapacity()

append()

附加一個元素到一個已經存在的陣列。

宣告

1
mutating func append(newElement: T)

使用

1
2
3
4
5
6
var array = [ 0 , 1 ]
array.append( 2 )
// array 的結果為 [0, 1, 2]
 
array.append( 3 )
// array 的結果為 [0, 1, 2, 3]

相同的,您無法附加一個元素,到一個常數陣列。

1
2
3
let constantArray = [ 0 , 1 ]
constantArray.append( 2 )
// 錯誤: immutable value of type '[Int]' only has mutating members named 'append'

insert(_ :, atIndex:)

插入一個元素,到陣列的特定位置。注意插入不是取代!

宣告

1
mutating func insert(newElement: T, atIndex: Int)

使用

在陣列的最前面插入 0。

1
2
3
var array = [ 1 , 2 , 3 ]
array.insert( 0 , atIndex: 0 )
// array 的結果為 [0, 1, 2, 3]

同樣的,不能超出陣列範圍。

1
2
array.insert( 6 , atIndex: 6 )
// 錯誤: Array replace: subRange extends past the end

一樣無法針對常數陣列做插入的動作。

1
2
3
let constantArray = [ 1 , 2 , 3 ]
constantArray.insert( 0 , atIndex: 0 )
// 錯誤: immutable value of type '[Int]' only has mutating members named 'insert'

removeAtIndex() -> T

移除特定元素。

宣告

1
mutating func removeAtIndex(index: Int) -> T

使用

移除陣列的第一個元素。

1
2
3
4
var array = [ 0 , 1 , 2 , 3 ]
let removed = array.removeAtIndex( 0 )
// array 結果為 [1, 2, 3]
// 0 被移除

同樣不可超出陣列範圍。

1
2
array.removeAtIndex( 5 )
// 錯誤: Array index out of range

常數陣列不可變動。

1
2
3
let constantArray = [ 0 , 1 , 2 ] constantArray.removeAtIndex( 0 )
// 錯誤: immutable value of type '[Int]' only has mutating members named
'removeAtIndex'

removeLast() -> T

移除陣列最後一個元素,並且回傳它。

宣告

1
mutating func removeLast() -> T

使用

1
2
3
4
var array = [ 1 , 2 , 3 ]
let removed = array.removeLast()
// array 的內容變為 [1, 2]
// removed 內容為 3

呼叫 removeLast 函式,陣列內必須至少有一個元素在裡面,否則將會出錯。

1
2
3
var emptyArray = [Int]()
let tryToRemove = emptyArray.removeLast()
// 錯誤: can't removeLast from an empty Array

常數陣列不可修改。

1
2
3
let constantArray = [ 1 , 2 ]
constantArray.removeLast()
// 錯誤: immutable value of type '[Int]' only has mutating members named 'removeLast'

removeAll(keepCapacity: = false)

移除陣列所有元素,預設為清空 storage buffer,除非特別指定keepCapacity。

宣告

1
mutating func removeAll(keepCapacity: Bool = false )

使用

1
2
3
4
var array = [ 0 , 1 , 2 , 3 ]
array.removeAll()
let count = array.count
// count 為 0

常數陣列無法更動。

1
2
3
let constantArray = [ 1 , 2 ]
constantArray.removeAll()
// 錯誤: immutable value of type '[Int]' only has mutating members named 'removeAll'

reserveCapacity()

設定陣列底層的儲存空間。

Array 在記憶體所展示的是一段連續記憶體空間,如果元素超過了此設定大小的空間,則必須重新配置空間來存放元素。

宣告

1
mutating func reserveCapacity(minimumCapacity: Int)

使用

1
2
3
var array = [ 0 , 1 , 2 , 3 ]
array.reserveCapacity( 10 )
// 將陣列空間設定到 10

陣列搜尋

  • var count { get }
  • var isEmpty { get }
  • var capacity { get }

var count { get }

回傳總共有幾個元素。

宣告

1
var count: Int { get }

使用

1
2
3
4
5
6
7
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)。

宣告

1
var isEmpty: Bool { get }

使用

1
2
3
4
5
6
7
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)。

宣告

1
var capacity: Int { get }

使用

1
2
3
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 語言裡頭也是扮演很重要的角色。之後的教學文章將會特別說明。

宣告

1
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 參數時,甚至不需要括號,如下範例,可讓程式碼更簡潔易讀。

1
2
3
4
5
6
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 會將排序結果,組成陣列回傳。

宣告

1
func sorted(isOrderedBefore: (T, T) -> Bool) -> Array<T>

使用

1
2
3
4
5
6
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>

回傳一個反向的陣列。

宣告

1
func reverse() -> Array<T>

使用

1
2
3
let array = [ 2 , 0 , 1 , 4 ]
let reversedArray = array.reverse()
// reversedArray = [4, 1, 0, 2]

filter(_ :) -> Array<T>

尋訪每個陣列內的元素,執行傳入的 Closure 回傳 ture 時,加入回傳結果的陣列。

宣告

1
func filter(includeElement: (T) -> Bool) -> Array<T>

使用

尋訪每個元素,留下二的倍數。

1
2
3
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 加以處理元素後,加入回傳的陣列當中。

宣告

1
func map<U>(transform: (T) -> U) -> Array<U>

使用

map 可將每個 陣列的元素加以處理,將每個元素乘上倍數,或將元素組成字串。

1
2
3
4
5
6
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

宣告

1
func reduce<U>(initial: U, combine: (U, T) -> U) -> U

使用

reduce 的用法,需給它一個初始值,接著在尋訪每個元素時,與每個元素計算結合為一個元素,以遞迴的方式,不斷的呼叫第二個參數,Closure 運算。

舉個例子:從 1 加到 5。

1
2
3
4
5
6
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 之前,可以任意附加元素或是陣列,但之後修改為,必須要是陣列與陣列才能附加。如同宣告方式所定義:

宣告

1
2
3
4
func +=<T, C : CollectionType where T == T>(inout lhs: _ContiguousArrayBuffer<T>, rhs: C)
 
// 舊的做法
@assignment func += <U>(inout lhs: Array<T>, rhs: U)

使用

此處用法注意 += 兩端皆需為陣列型態。

1
2
3
4
5
6
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。

宣告

1
init(minimumCapacity: Int = 2 )

使用

1
2
var emptyDictionary = Dictionary<String, Int>()
// 建立一個空的字典,鍵值形態為String,數值形態為Int。

這兩種宣告方式的結果是一樣的。

1
var equivalentEmptyDictionary = [String: Int]()

存取、修改字典內容

  • subscript (key: Key) -> Value?
  • updateValue(_:, forKey:) -> Value?
  • removeValueForKey(_:) -> Value?
  • removeAll(keepCapacity: = false)

subscript (key: Key) -> Value?

下標語法subscript在陣列與字典都很常用,而且直覺,許多語言大多都是以這樣的方式存取。

宣告

1
subscript (key: Key) -> Value?

使用

1
2
3
var dictionary = [ "one" : 1 , "two" : 2 , "three" : 3 ]
let value = dictionary[ "two" ]
// 所以回傳的 value 會是一個 optional 帶著 2 這個數值。

這邊用到的是一種 Optional 特殊寫法,叫做 Optional Binding,訣竅是 if let,若 Optional 有值 會直接賦予到變數當中,若沒有值,則為 false 條件不成立。這樣我們就不用猜測變數究竟會是什麼型態,而寫出許多判斷式,我們稱之為防禦性編程(Defensive Programming),減少這類的程式碼,問題與臭蟲相對較少,開發者也能更專注在資料流與商業邏輯。

1
2
3
4
if let unwrappedValue = dictionary[ "three" ] {
     println( "字典透過鍵值 \"three\" 取出的值是 \(unwrappedValue)" )
}
// prints "字典透過鍵值 "three" 取出的值是 3"

能用下標語法取值,同樣也能用來更新數值。

1
2
3
4
5
6
7
8
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]

若字典定義為常數,修改的下標語法將無法使用!

1
2
3
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?

插入或更新字典數值,第一個參數為更新的數值,第二個參數為鍵值,並回傳將被取代的數值。

宣告

1
mutating func updateValue(value: Value, forKey key: Key) -> Value?

使用

1
2
3
var dictionary = [ "one" : 1 , "two" : 2 , "three" : 3 ]
let previousValue = dictionary.updateValue( 22 , forKey: "two" )
// previousValue 將會是個 Optional 型態,帶著 2 這個數值。

若用 Optional Binding 方式表達,則範例如下:

1
2
3
4
5
6
7
if let unwrappedPreviousValue = dictionary.updateValue( 33 , forKey: "three" ) {
     println( "取代的數值為 \(unwrappedPreviousValue)" )
}
else {
     println( "這是一個新的 key-value " )
}
// prints "取代的數值為 3"

removeValueForKey(_:) -> Value?

傳入鍵值,移除該組 key-value,並且回傳被移除的數值。

宣告

1
mutating func removeValueForKey(key: Key) -> Value?

使用

1
2
3
var dictionary = [ "one" : 1 , "two" : 2 , "three" : 3 ]
let previousValue = dictionary.removeValueForKey( "two" )
// previousValue 將會是個 Optional 型態,帶著 2 這個數值。

removeValueForKey 將回傳被移除的數值。

1
2
3
4
5
6
7
 if let unwrappedPreviousValue = dictionary.removeValueForKey( "three" ) {
     println( "移除的數值為 \(unwrappedPreviousValue)" )
}
     else {
     println( "找不到可以刪除的值" )
}
// prints "移除的數值為 3"

removeAll(keepCapacity: = false)

移除字典內所有 key-value 數值,預設為清空 storage buffer,除非特別指定keepCapacity。

宣告

1
mutating func removeAll(keepCapacity: Bool = default )

使用

1
2
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。

宣告

1
var count: Int { get }

使用

1
2
3
var dictionary = [ "one" : 1 , "two" : 2 , "three" : 3 ]
let elementCount = dictionary.count
// elementCount 等於 3

var keys { get }

這是個唯讀的函式,回傳所有鍵值,並且為 CollectionType。

宣告

1
var keys: LazyBidirectionalCollection<MapCollectionView<[Key : Value], Key>> { get }

使用

使用 for-in 迴圈尋訪每個鍵值,並且印出來。

1
2
3
4
5
6
7
8
var dictionary = [ "one" : 1 , "two" : 2 , "three" : 3 ]
for key in dictionary.keys {
     println(key)
}
// 結果印出:
// one
// two
// three

轉為 Array 即可使用 Array 的函式。

1
2
let array = Array(dictionary.keys)
// array is ["one", "two", "three"]

var values { get }

回傳字典內所有數值,這是個未排序的數值 collection。

宣告

1
var values: LazyBidirectionalCollection<MapCollectionView<[Key : Value], Value>> { get }

使用

1
2
3
4
5
6
7
8
var dictionary = [ "one" : 1 , "two" : 2 , "three" : 3 ]
for value in dictionary.values {
     println( "數值: \(value)" )
}
// 結果印出:
// 數值: 1
// 數值: 2
// 數值: 3

轉為 Array 即可使用 Array 的函式。

1
2
let array = Array(dictionary.values)
// array is [1, 2, 3]

字典的運算元

  • ==
  • !=

==

判斷字典內容是否相等。

宣告

1
func ==<Key : Equatable, Value : Equatable>(lhs: [Key : Value], rhs: [Key : Value]) -> Bool

使用

定義一個 dictionary1 的字典常數,然後跟一個 dictionary2 的字典比較,內容相同為 true。

1
2
3
4
5
let dictionary1 = [ "one" : 1 , "two" : 2 ]
var dictionary2 = [ "one" : 1 ]
dictionary2[ "two" ] = 2
let result = dictionary1 == dictionary2
// 結果為 true

!=

用法與==相同,只不過意思相反,用來比較字典內容是否不相同。

宣告

1
func !=<Key : Equatable, Value : Equatable>(lhs: [Key : Value], rhs: [Key : Value]) -> Bool

使用

因為 dictionary1 與 dictionary2 內容完全不同,所以結果為 true。

1
2
3
4
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-128127
Int16-32,76832,767
Int32-2,147,483,6482,147,483,647
Int64-9,223,372,036,854,775,8089,223,372,036,854,775,807
UInt80255
UInt16065,535
UInt3204,294,967,295
UInt64018,446,744,073,709,551,615

Floating Point Types

在 Swift 主要的浮點數型態為 Double,使用的是 64bit的精準度,當然也可以使用32bit精準度的 Float。

Protocols

  • Equatable
  • Comparable
  • Printable

我們將介紹 Swift 語言裡面,最基礎常見的三個Protocols(協定)。

Equatable

判斷是否相等

==

宣告

1
func == (lhs: Self, rhs: Self) -> Bool

使用

底下定義一個 struct 叫 MyStruct,遵從 Equatable 協定,我們必須在全域環境底下實作 ==function,並且回傳布林值 true 代表相等,false 則不相等。

我們實作==function,讓它判斷MyStructname相同時,代表相等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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,是的就是<,當實作完<==,您將自動獲得 <=>=> 這三個比較運算元!

宣告

1
2
3
4
5
6
7
8
9
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
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 }

宣告

1
2
3
protocol Printable {
     var description: String { get }
}

使用

1
2
3
4
5
6
7
8
9
10
11
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)印出。

宣告

1
func print<T>(object: T)

使用

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

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

println<T>(_:)

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

宣告

1
func println<T>(object: T)

使用

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

1
2
println( "Hello, world" )
// 印出 "Hello, world" 並斷行

println()

直接在標準輸出,印出斷行。

宣告

1
func println()

使用

直接呼叫使用。

1
2
3
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協定,傳入陣列的元素,必須遵循此協定才能比較並排序。

宣告

1
func sort<T: Comparable>(inout array: T[])

使用

此處宣告的 sort function 傳入的參數陣列前面多了一個inout關鍵字,這代表的意思是,此處傳入的參數 是可以被修改並替換的。

現在將陣列傳入一個,inout參數的函式,必須將參數明確表示,在變數前面必須加上&

1
2
3
var array = [ 5 , 1 , 6 , 4 , 2 , 3 ]
sort(&array)
// array 排序後,並且被替換為 [1, 2, 3, 4, 5, 6]

常數無法被丟進inout參數處理。

1
2
3
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,將排在前面,反之往後排序。

宣告

1
func sort<T>(inout array: [T], isOrderedBefore: (T, T) -> Bool)

使用

1
2
3
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則是回傳結果陣列,不去更動原來的陣列物件。

宣告

1
func sorted<C : MutableCollectionType where C.Index : RandomAccessIndexType, C.Generator.Element : Comparable>(source: C) -> C

使用

因為不需更動array物件,所以此處 array 前面不需加&

1
2
3
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,將排在前面,反之往後排序。

宣告

1
func sorted<C : MutableCollectionType where C.Index : RandomAccessIndexType>(source: C, isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool) -> C

使用

1
2
3
let array = [ 5 , 1 , 3 , 4 , 2 , 6 ]
let result = sorted(array) { $ 0 > $ 1 }
// result陣列,排序結果為 [6, 5, 4, 3, 2, 1]

按讚!加入 CodeData Facebook 粉絲群 
name="f25917039c" width="1000px" height="1000px" frameborder="0" allowtransparency="true" scrolling="no" title="fb:like Facebook Social Plugin" src="http://www.facebook.com/plugins/like.php?action=like&app_id=476701695701128&channel=http%3A%2F%2Fstatic.ak.facebook.com%2Fconnect%2Fxd_arbiter%2F7r8gQb8MIqE.js%3Fversion%3D41%23cb%3Df3b460f4a8%26domain%3Dwww.codedata.com.tw%26origin%3Dhttp%253A%252F%252Fwww.codedata.com.tw%252Ff30e85411%26relation%3Dparent.parent&color_scheme=light&href=https%3A%2F%2Fwww.facebook.com%2Fcodedata.tw&layout=button&locale=zh_TW&sdk=joey&show_faces=false" style="position: absolute; border-style: none; visibility: visible; width: 0px; height: 0px;">
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值