提出問題
優秀的泛型使用案例中,最多見的例子當屬對棧(Stack) 的操做。棧做爲容器有兩種操做:一.壓入(Push) 操做添加項到容器中;二.彈出(Pop) 操做將最近添加項從容器移除。首先咱們用非泛型方式設計棧 。最後代碼以下所示:web
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class IntStack { private var stackItems:[Int ] = [] func pushItem (item:Int) { stackItems.append(item) } func popItem () ->Int ?{ let lastItem = stackItems.last stackItems.removeLast() return lastItem } }
該棧可以處理Int 類型數據。這看起來不錯,可是假若要創建一個可以處理String
類型的棧 ,咱們又該如何實現呢?咱們須要替換全部Int
爲String
,不過這顯然是一個糟糕的解決方法。此外另一種方法乍看之下灰常不錯,以下:編程
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class AnyObjectStack { private var stackItems:[AnyObject ] = [] func pushItem (item:AnyObject) { stackItems.append(item) } func popItem () ->AnyObject ?{ let lastItem = stackItems.last stackItems.removeLast() return lastItem } }
此處,咱們合理地使用AnyObject
類型,那麼如今可以將String
類型數據壓入到棧中了,對麼?不過這種狀況下咱們就失去了數據類型的安全,而且每當咱們對棧進行操做時,都須要進行一系列繁瑣的類型轉換(casting
操做,使用as
來進行類型轉換)。swift
解決方案
參照泛型的特性,咱們可以定義一個泛型類型,這看起來像一個佔位符。使用泛型後的示例代碼以下:數組
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class Stack <T > { private var stackItems: [T ] = [] func pushItem (item:T) { stackItems.append(item) } func popItem () -> T ? { let lastItem = stackItems.last stackItems.removeLast() return lastItem } }
泛型定義方式:由一對尖括號(<>
)包裹,命名方式一般爲大寫字母開頭(這裏咱們命名爲T
)。在初始化階段,咱們經過明確的類型(這裏爲Int
)來定義參數,以後編譯器將全部的泛型T
替換成Int
類型:安全
1 2 3 4 5 6 7 8
let aStack = Stack <Int >()aStack.pushItem(10 ) if let lastItem = aStack.popItem() { print ("last item: \(lastItem) " ) }
如此實現的棧,最大優點在於可以匹配任何類型。app
類型約束
這裏存在一個缺點:儘管泛型可以表明任何類型,咱們對它的操做也是比較有侷限性的。僅僅是比較兩個泛型都是不支持的,請看以下代碼:編程語言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
class Stack <T > { private var stackItems: [T ] = [] func pushItem (item:T) { stackItems.append(item) } func popItem () -> T ? { let lastItem = stackItems.last stackItems.removeLast() return lastItem } func isItemInStack (item:T) -> Bool { var found = false for stackItem in stackItems { if stackItem == item { found = true } } return found } }
注意到函數isItemInSatck(item:T)
中,咱們獲得了一個編譯錯誤,由於兩個參數沒有實現Equtable
協議的話,類型值是不能進行比較的。實際上咱們能夠爲泛型增長約束條件來解決這個問題。在本例中,經過對第一行進行修改,咱們讓泛型T
遵循Equatable
協議:函數
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
class Stack <T :Equatable > { private var stackItems: [T ] = [] func pushItem (item:T) { .append(item) } func popItem () -> T ? { let lastItem = stackItems.last stackItems.removeLast() return lastItem } func isItemInStack (item:T) -> Bool { var found = false for stackItem in stackItems { if stackItem == item { ound = true } } return found } }
總結
就像衆多其餘編程語言同樣,你也可以在Swift
中利用泛型這一特性。假若你想要寫一個庫,泛型是很是好用的特性。ui