如果學過java就知道泛型是什么 比如說定義一個數組 var a : [Int]
Int 就是該數組的泛型 創建一個字典也是根據泛型儲存內容的
var a : Dictionary <String,String>
而泛型能解決的問題 就像字典一樣 他是個不確定的鍵值對 你定義什么類型就能存什么類型
泛型函數
下面舉個例子一個函數 要將兩個參數值互換
func myswap(inout a: Int,inout b: Int) { let temp = a a = b b = temp
}
如上所寫 只能交換int類型數據 如果要String類型呢 是不是又要另外寫一份?
這里用泛型就省力了 把參數類型改成未知的一個泛型一般用 "T"
func myswap<T>(inout a: T,inout b: T) { let temp = a a = b b = temp }
語法就不多解釋了 尖括號寫的是泛型 形參用就可以了
這樣只要滿足運算符"="操作的類型就能交換
泛型類型
在類或結構中定義一個泛型類型 下面舉個栗子
class Stack<Element> { var containers = [Element]() func push(e: Element) { containers.append(e) } func pop() -> Element { return containers.removeLast() } }
var data: Stack<Int> = Stack<Int>()
這個類是模仿棧的結構有push入棧與pop出棧兩個方法
類中的數組在類實例化時決定
泛型擴展
擴展時,不需要再指定泛型參數(尖括號里面的內容稱之為泛型參數)
extension Stack { var count: Int { return containers.count }
func aa(e:Element){
print(e)
}
}
var data2 = Stack<String>()
data2.push("dasdf")
data2.count
泛型約束
你可以寫一個在一個類型參數名后面的類型約束,通過冒號分割,來作為類型參數鏈的一部分。這種作用於泛型函數的類型約束的基礎語法如下所示(和泛型類型的語法相同):
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // function body goes here }
上面這個假定函數有兩個類型參數。第一個類型參數T
,有一個需要T
必須是SomeClass
子類的類型約束;第二個類型參數U
,有一個需要U
必須遵循SomeProtocol
協議的類型約束。
用處也跟泛型函數類似 比如寫一個查找數組中是否有該數 有則返回下標 沒有則返回-1
func index<T:Equatable>(arr:[T],data: T) ->Int { for (m,n) in arr.enumerate() { if n == data { return m } } return -1 }
這樣寫也就意味着“任何T類型都遵循Equatable
協議” 如果有多個需要約束的協議則在Eqatableh
where T:類型,T:類型....
協議的關聯類型修飾符 typealias
定義協議時我們無法聲明泛型 所以在協議中泛型寫法變了一下
protocol Containter { typealias Element mutating func push(e: Element) mutating func pop()-> Element }
實現該協議
struct MyStack: Containter{ // typealias Element = Int var containers = [Int]() mutating func push(e: Int) { containers.append(e) } mutating func pop() -> Int { return containers.removeLast() } }
實現時經過swift類型推斷 實現為 Element = Int
實現后更改泛型名稱也是可以的
struct Stack<Element,Com>: Containter { //按照當前的實現,下面的代碼由於類型推斷,可以省略 //typealias Element = E var containers = [Element]() var com=[Com]() mutating func push(e: Element) { containers.append(e) } mutating func pop() -> Element { return containers.removeLast() } }
擴展協議時的約束以及協議關聯類型的使用
//定義兩個協議MM,NN protocol MM { } protocol NN : MM{ } //分別實現協議MMClass,NNClass class MMClass: MM { } class NNClass: NN { } //定義f泛型協議Container protocol Container { typealias ItemType } //擴展泛型協議Container的泛型 使其受MM協議約束 extension Container where ItemType: MM { var b: Int {return 5} } //擴展泛型協議Container的泛型 使其受NN協議約束 extension Container where ItemType: NN { var b: Int {return 6} } //TestTest類實現Container協議 class TestTest: Container { typealias ItemType = MMClass //如果這里改為MMClass,那么aaaa.b輸出結構是5 } class TestTest2: Container { typealias ItemType = Int //若泛型類型的值不滿足任何一個協議則無法訪問b屬性 } let aaaa = TestTest() aaaa.b let bbbb = TestTest2() bbbb.b//報錯