泛型可以讓開發者編寫自定義需求已經任意類型的靈活可用的的函數和類型。可以讓咱們避免重複的代碼。用一種清晰和抽象的方式來表達代碼的意圖。swift
func swapTwoStrings(_ a: inout String, _ b: inout String) { let temporaryA = a a = b b = temporaryA } func swapTwoDoubles(_ a: inout Double, _ b: inout Double) { let temporaryA = a a = b b = temporaryA }
從以上代碼來看,它們功能代碼是相同的,只是類型上不同,這時咱們可使用泛型,從而避免重複編寫代碼。數組
泛型使用了佔位類型名(在這裏用字母 T 來表示)來代替實際類型名(例如 Int、String 或 Double)。app
func swapTwoValues<T>(_ a: inout T, _ b: inout T)
備註:這個函數功能是用來交換兩個一樣類型的值,可是這個函數用T佔位符來代替實際的類型。並無指定具體的類型,可是傳入的a,b必須是同一個類型T。在調用這個函數d的時候才能指定T是哪一種具體的類型。還有函數名後面跟的那個<T>是函數定義的一個佔位符類型名,並不會查找T的具體類型。使用該函數只要保證傳入的兩個參數是同一個類型,就不用根據傳入參數的類型不一樣,而寫不一樣的方法。ide
看泛型在代碼用,是如何使用的。函數
override func viewDidLoad() { super.viewDidLoad() //swift泛型 var num1 = 100 var num2 = 200 print("交換前數據: \(num1) 和 \(num2)") swapTwoValue(&num1, &num2) print("交換後數據: \(num1) 和 \(num2)") var str1 = "ABC" var str2 = "abc" print("交換前數據: \(str1) 和 \(str2)") swapTwoValue(&str1, &str2) print("交換後數據: \(str1) 和 \(str2)") } func swapTwoValue<T>(_ a : inout T,_ b : inout T) { let temp = a a = b b = temp }
泛型約束大體分爲如下幾種:spa
(1)繼承約束,泛型類型必須是某個類的子類型3d
(2)協議約束,泛型類型必須遵循某些協議code
(3)條件約束,泛型類型必須知足某種條件blog
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // 這裏是泛型函數的函數體部分 }
//定義一個父類,動物類 class Animal{ //動物都會跑 func run(){ print("Animal run") } } //定義狗類,繼承動物類 class Dog: Animal { override func run(){//重寫父類方法 print("Dog run") } } //定義貓類,繼承動物類 class Cat: Animal { override func run(){//重寫父類方法 print("Cat run") } } //定義泛型函數,接受一個泛型參數,要求該泛型類型必須繼承Animal func AnimalRunPint<T:Animal>(animal:T){ animal.run() //繼承了Animal類的子類都有run方法能夠調用 } AnimalRunPint(animal: Dog()) AnimalRunPint(animal: Cat())
//定義泛型函數,爲泛型添加協議約束,泛型類型必須遵循Equatable協議 func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? { var index = 0 for value in array { if value == valueToFind {//由於遵循了Equatable協議,因此能夠進行相等比較 return index } else { index += 1 } } return nil } //在浮點型數組中進行查找,Double默認遵循了Equatable協議 let doubleIndex = findIndex(array: [3.14159, 0.1, 0.25], valueToFind: 9.3) if let index = doubleIndex { print("在浮點型數組中尋找到9.3,尋找索引爲\(index)") } else { print("在浮點型數組中尋找不到9.3") } //在字符串數組中進行查找,String默認遵循了Equatable協議 let stringIndex = findIndex(array: ["Mike", "Malcolm", "Andrea"], valueToFind: "Andrea") if let index = stringIndex { print("在字符串數組中尋找到Andrea,尋找索引爲\(index)") } else { print("在字符串數組中尋找不到Andrea") }
//添加泛型條件約束,C1和C2必須遵循Stackable協議,並且C1和C2包含的泛型類型要一致 func pushItemOneToTwo<C1: Stackable, C2: Stackable>( stackOne: inout C1, stackTwo: inout C2) where C1.ItemType == C2.ItemType {//由於C1和C2都遵循了Stackable協議,纔有ItemType屬性能夠調用 let item = stackOne.pop() stackTwo.push(item: item) } //定義另一個結構體類型,一樣實現Stackable協議,實際上裏面的實現和Stack同樣 struct StackOther<T>: Stackable{ var store = [T]() mutating func push(item:T){//實現協議的push方法要求 store.append(item) } mutating func pop() -> T {//實現協議的pop方法要求 return store.removeLast() } } //建立StackOther結構體,泛型類型爲String var stackTwo = StackOther<String>() stackTwo.push(item: "where") //雖然stackOne和stackTwo類型不同,但泛型類型同樣,也一樣遵循了Stackable協議 pushItemOneToTwo(stackOne: &stackOne, stackTwo: &stackTwo ) print("stackOne = \(stackOne.store), stackTwo = \(stackTwo.store)") //打印:stackOne = ["hello"], stackTwo = ["where", "swift"]