1.為什么需要泛型的使用
其實說白了很簡單。就是對于方法結構相同,但是由于類型不同,而需要多次重寫這些類似的方法的一種解決方案。
2.泛型的函數
看如下代碼:
func swapInInts(inout a: Int, inout b: Int) { let temp = a a = b b = temp }
如上: 就是一個交換數值的方法,但是如果我現在也想對String類型,Double,Float等類型都做這樣的操作,你一定想,tm寫那么多類似的code真是麻煩。所以此時糊涂貓想只能用一種萬能的方法解決這種類似的方法體。
泛型出現了
func swapInValues<T>(inout a:T, inout b: T) { let temp = a a = b b = temp }
現在使用起來就好贊,不經可以使用Int,String,Float等類型都可以
var a = 15 var b = 20 swapInValues(&a, &b)
3.類型參數
如上可以看到<T>
,其中類型T
是一個類型占位符,一般情況下我們是使用T來代表,但是其實是可以用任意符號表示。
4.泛型類型---實現一種較為復雜的數據結構
泛型是一種類型
實現棧的結構
非泛型
struct Stack { var items: [Int] = [Int]() mutating func push(item: Int) { items.append(item) } mutating func pop() -> Int { return items.removeLast() }
泛型
struct Stack<T> { var items: [T] = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } }
使用如下
var stackOfStrings = Stack<String>() stackOfStrings.push("uno") // push a item to stack stackOfStrings.push("dos") stackOfStrings.push("tres") stackOfStrings.push("cuatro") let resultOfPop = stackOfStrings.pop() // pop a item
5.類型約束
泛型給我門極大的自由度,那為什么要對類型進行約束呢?
泛型最初的是為了突破類型的限制,使code的復用率更高。但是并不是什么地方都適用所有類型的,因此對類型做約束就顯得非常的重要。
類型約束的語法
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // function body goes here }
其中的T分別必須SomeClass類型或其子類的類型,U必須是遵循了SomeProtocol的對象。
這個概念是有些難懂,看如下一個看似沒問題,但是不能通過編譯的例子
func findIndex<T>(array: [T], findValue: T) -> Int? { for (index, value) in EnumerateSequence(array) { if value == findValue { return index } } return nil }
如上code,僅僅只是定義了一個泛型函數,去遍歷數組中的(index, value),最后返回數組中指定的索引即可。
但是,在編譯的時候,會報一個錯誤,譯為不能確定value和findValue是否能"=="操作符來進行判斷(比如自定義類型,Swift不能判斷復雜的結構....)。
但是Swift給了我們很好的解決方案,只需要對類型做一個限制,讓該類型實現可比較協議(Equatable)。 意味著任何T類型都遵循Equatable協議,如下所示
func findIndex<T: Equatable>(array: [T], findValue: T) -> Int? { for (index, value) in EnumerateSequence(array) { if value == findValue { return index } } return nil }
6.關聯類型
當定義一個協議時,有的時候聲明一個或多個關聯類型作為協議定義的一部分是非常有用的。一個關聯類型作為協議的一部分,給定了類型的一個占位名(或別名)。作用于關聯類型上實際類型在協議被實現前是不需要指定的。關聯類型被指定為typealias關鍵字。
協議定義一個關聯類型
protocol Container { typealias ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } }
非泛型的實現版本
struct IntStack: Container { // IntStack的原始實現 var items = [Int]() mutating func push(item: Int) { items.append(item) } mutating func pop() -> Int { return items.removeLast() } // 遵循Container協議的實現 typealias ItemType = Int mutating func append(item: Int) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> Int { return items[i] } }
泛型版本的實現
struct IntStack<T>: Container { // IntStack的原始實現 var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // 遵循Container協議的實現 typealias ItemType = T //可以不用顯示的聲明賦值 mutating func append(item: ItemType) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> ItemType { return items[i] } }