泛型
- 一個案例引發的思考
func swapTwoInts(_ a: inout Int, _ b: inout Int) { let temporaryA = a a = b b = temporaryA } var oneInt = 3 var twoInt = 4 swapTwoInts(&oneInt, &twoInt) print(oneInt,twoInt)
如果此時我們想交換兩個Double類型、或者是其他類型的值,就需要針對不同的類型寫類似的方法,但是這些方法僅僅只是參數類型不同。如何解決?—— 泛型
//泛型函數 func swapTwoValues<T>(_ a: inout T, _ b: inout T) { let temporaryA = a a = b b = temporaryA } var oneInt = 3 var twoInt = 4 swapTwoValues(&oneInt, &twoInt) print(oneInt,twoInt) var oneStr = "hello" var twoStr = "world" swapTwoValues(&oneStr, &twoStr) print("oneStr:\(oneStr),twoStr:\(twoStr)") var oneDouble = 10.01 var twoDouble = 20.02 swapTwoValues(&oneDouble, &twoDouble) print("oneDouble:\(oneDouble),twoDouble:\(twoDouble)")
類型參數
類型參數指定並命名一個佔位符類型,並用<>包裹,放在函數名後面,如上面例子中的 T
。可以用它來指定參數類型,或者返回值的類型。在真正調用的時候會被實際的類型替代,如傳遞的是Int,就替換爲Int,如果傳入的是Double類型就替換爲Double等等
類型約束
- 上面的
swapTwoValues(_:_:)
函數可以用於任意類型。但是,有時在用於泛型函數需要遵循特定的類型。 - 類型約束指出一個類型形式參數必須繼承自特定類,或者遵循一個特定的協議、組合協議。
- 語法
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { }
關聯類型
- 關聯類型通過 associatedtype 關鍵字指定
- Element 起到了佔位符的作用,指示了某種類型
- 在實現的時候不能直接用 Element
- Element 在遵守協議中協議方法中明確泛型的類型
protocol SomeProtocol { associatedtype Element func method1(element: Element) func method2(element: Element) } struct TestStruct: SomeProtocol { func method1(element: String) { print("method1: \(element)") } func method2(element: String) { print("method2: \(element)") } } TestStruct().method1(element: "Hello") TestStruct().method2(element: "World")
給關聯類型添加約束
//要遵循這個版本的 Container ,容器的 Item 必須遵循 Equatable 協議 protocol SomeProtocol { associatedtype Element: Equatable func method1(element: Element) func method2(element: Element) }
泛型where分句
- 泛型 where 分句能夠要求一個關聯類型必須遵循指定的協議,或者指定的類型形式參數和關聯類型必須相同
- 泛型 where 分句以 where 關鍵字開頭
protocol SomeProtocol { func say() } struct Bird: SomeProtocol { func say() { print("Hello") } } func genericFunc<T>(num: T) where T: SomeProtocol { print(num) } genericFunc(num: Bird())