作者:Thomas Hanning燎窘,原文鏈接,原文日期:2015/09/09
譯者:pmst蹄咖;校對:numbbbbb褐健;定稿:shanks
Objective-C
缺乏一個重要特性:不支持泛型。幸運地是澜汤,Swift
擁有這一特性蚜迅。泛型允許你聲明的函數(shù)、類以及結(jié)構(gòu)體支持不同的數(shù)據(jù)類型俊抵。
提出問題
優(yōu)秀的泛型使用案例中谁不,最常見的例子當(dāng)屬對棧(Stack)的操作。棧作為容器有兩種操作:一.壓入(Push)操作添加項到容器中;二.彈出(Pop)操作將最近添加項從容器移除徽诲。首先我們用非泛型方式設(shè)計棧刹帕。最后代碼如下所示:
class IntStack{
// 采用數(shù)組作為容器保存數(shù)據(jù) 類型為Int
private var stackItems:[Int] = []
// 入棧操作 即Push 添加最新數(shù)據(jù)到容器最頂部
func pushItem(item:Int){
stackItems.append(item)
}
// 出棧操作 即Pop 將容器最頂部數(shù)據(jù)移除
func popItem()->Int?{
let lastItem = stackItems.last
stackItems.removeLast()
return lastItem
}
}
該棧能夠處理Int類型數(shù)據(jù)。這看起來不錯谎替,但是倘若要建立一個能夠處理String
類型的棧偷溺,我們又該如何實現(xiàn)呢?我們需要替換所有Int
為String
钱贯,不過這顯然是一個糟糕的解決方法挫掏。此外另外一種方法乍看之下灰常不錯,如下:
class AnyObjectStack{
// 采用數(shù)組作為容器保存數(shù)據(jù) 類型為AnyObject
private var stackItems:[AnyObject] = []
// 入棧操作 即Push 添加最新數(shù)據(jù)到容器最頂部
func pushItem(item:AnyObject){
stackItems.append(item)
}
// 出棧操作 即Pop 將容器最頂部數(shù)據(jù)移除
func popItem()->AnyObject?{
let lastItem = stackItems.last
stackItems.removeLast()
return lastItem
}
}
此處秩命,我們合理地使用AnyObject
類型尉共,那么現(xiàn)在能夠?qū)?code>String類型數(shù)據(jù)壓入到棧中了,對么硫麻?不過這種情況下我們就失去了數(shù)據(jù)類型的安全爸邢,并且每當(dāng)我們對棧進行操作時,都需要進行一系列繁瑣的類型轉(zhuǎn)換(casting
操作,使用as
來進行類型轉(zhuǎn)換)。
解決方案
參照泛型的特性拿愧,我們能夠定義一個泛型類型杠河,這看起來像一個占位符。使用泛型后的示例代碼如下:
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
)來定義參數(shù),之后編譯器將所有的泛型T
替換成Int
類型:
// 指定了泛型T 就是 Int
// 編譯器會替換所有T為Int
let aStack = Stack<Int>()
aStack.pushItem(10)
if let lastItem = aStack.popItem() {
print("last item: \(lastItem)")
}
如此實現(xiàn)的棧柳洋,最大優(yōu)勢在于能夠匹配任何類型待诅。
類型約束
這里存在一個缺點:盡管泛型能夠代表任何類型,我們對它的操作也是比較有局限性的熊镣。僅僅是比較兩個泛型都是不支持的卑雁,請看如下代碼:
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
}
}
注意到函數(shù)isItemInSatck(item:T)
中募书,我們得到了一個編譯錯誤,因為兩個參數(shù)沒有實現(xiàn)Equtable
協(xié)議的話测蹲,類型值是不能進行比較的莹捡。實際上我們可以為泛型增加約束條件來解決這個問題。在本例中扣甲,通過對第一行進行修改篮赢,我們讓泛型T
遵循Equatable
協(xié)議:
class Stack<T:Equatable> {
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
}
}
總結(jié)
就像眾多其他編程語言一樣,你也能夠在Swift
中利用泛型這一特性琉挖。倘若你想要寫一個庫启泣,泛型是非常好用的特性。