They said "you should learn a new language every year," so I learned Swift. Now I learn a new language every two weeks!
這個笑話絕對是我看過的Swift被黑的最慘的一次!所以今天我們來學習一下Swift的泛型。
Swift的泛型有點奇怪,針對Class和Function,都是通過<Type>來定義,和C#一摸一樣,同樣也有where關鍵字進行約束。
func swapTwoValues<T>(inout a: T, inout _ b: T) { let temporaryA = a a = b b = temporaryA } class CanPrintBase<T> { func PrintType(output: T) -> Void {} }
但是面對Interface,也就是Swift里的Protocol,需要使用associatedtype關鍵字來定義泛型:
protocol CanPrint { associatedtype E func PrintType(output: E) -> Void }
那要怎么去實現這個接口呢?通常是這樣子的:
class TypePrinter0 : CanPrint{ typealias E = String func PrintType(output: E) { print(type(of:output)) } } let print0 = TypePrinter0() print0.PrintType(output: "String Type")
然后就會在output窗口打印“String”。
阿西吧!這么奇怪的語法簡直不能忍!就不能用<Type>來寫嗎?
曲線救國的話,我們可以考慮模擬一個抽象類class CanPrintBase<T>,通過繼承來實現同樣的效果:
class TypePrinter3: CanPrintBase<String>{ override func PrintType(output: String){ print(type(of:output)) } } let print3 = TypePrinter3() print3.PrintType(output: "String Type")
那么我們像C#一樣直接在類定義的時候通過占位符的方式可以嘛?
//This one cannot work! class TypePrinter1<E: String> : CanPrint{ func PrintType(output: E) { print(output) } }
錯誤提示為:Inheritance from non-protocol, non-class type 'String'。也就是說如果是class類型的話就可以:
public class SomeType {} class TypePrinter2<E: SomeType> : CanPrint{ func PrintType(output: E) { print(output) } } let print2 = TypePrinter2() print2.PrintType(output: SomeType())
反之我們也可以寫成這樣:
class TypePrinter5 : CanPrint{ typealias E = SomeType func PrintType(output: E) { print(output) } } let print5 = TypePrinter5(); print(type(of: print5)) print(type(of: print2))
將類型打印出來的話,分別是TypePrinter5和TypePrinter2<SomeType>,也就是說這兩種寫法得到的類型是完全不一樣的。
呵呵也是蠻妖的嘛,還可以把類型的具體定義留到使用時再聲明:
class TypePrinter4<E> : CanPrint{ func PrintType(output: E) { print(output) } } let print4 = TypePrinter4<SomeType>() print4.PrintType(output: SomeType()) let print6 = TypePrinter4<String>() print6.PrintType(output: "I am a String")
這一點又和C#傻傻分不清楚了。
本篇實在是蠻無聊的糾纏與Swift泛型協議的語法,如孔乙己般嘗試了回字的N種寫法。至於為什么Swift要這么設計,我們下一篇可以嘗試和C#對比看看。
GitHub:
https://github.com/manupstairs/LearnSwift/tree/master/GenericProtocolTest