Swift泛型類型
泛型類型
通常在泛型函數中,Swift 允許你定義你自己的泛型類型。這些自定義類、結構體和枚舉作用於任何類型,如同Array
和Dictionary
的用法。
這部分向你展示如何寫一個泛型集類型--Stack
(棧)。一個棧是一系列值域的集合,和Array
(數組)類似,但其是一個比 Swift 的Array
類型更多限制的集合。一個數組可以允許其裏面任何位置的插入/刪除操作,而棧,只允許在集合的末端添加新的項(如同push一個新值進棧)。同樣的一個棧也只能從末端移除項(如同pop一個值出棧)。
注意
棧的概念已被UINavigationController
類使用來模擬試圖控制器的導航結構。你通過調用UINavigationController
的pushViewController:animated:
方法來爲導航棧添加(add)新的試圖控制器;而通過popViewControllerAnimated:
的方法來從導航棧中移除(pop)某個試圖控制器。每當你需要一個嚴格的後進先出
方式來管理集合,堆棧都是最實用的模型。
下圖展示了一個棧的壓棧(push)/出棧(pop)的行爲:
- 現在有三個值在棧中;
- 第四個值「pushed」到棧的頂部;
- 現在有四個值在棧中,最近的那個在頂部;
- 棧中最頂部的那個項被移除,或稱之爲「popped」;
- 移除掉一個值後,現在棧又重新只有三個值。
這裏展示瞭如何寫一個非泛型版本的棧,Int
值型的棧:
struct IntStack {
var items = Int[]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
這個結構體在棧中使用一個Array
性質的items
存儲值。Stack
提供兩個方法:push
和pop
,從棧中壓進一個值和移除一個值。這些方法標記爲可變的,因爲它們需要修改(或轉換)結構體的items
數組。
上面所展現的IntStack
類型只能用於Int
值,不過,其對於定義一個泛型Stack
類(可以處理任何類型值的棧)是非常有用的。
這裏是一個相同代碼的泛型版本:
struct Stack<T> {
var items = T[]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
注意到Stack
的泛型版本基本上和非泛型版本相同,但是泛型版本的佔位類型參數爲T代替了實際Int
類型。這種類型參數包含在一對尖括號裏(<T>
),緊隨在結構體名字後面。
T
定義了一個名爲「某種類型T」的節點提供給後來用。這種將來類型可以在結構體的定義裏任何地方表示爲「T」。在這種情況下,T
在如下三個地方被用作節點:
- 創建一個名爲
items
的屬性,使用空的T類型值數組對其進行初始化; - 指定一個包含一個參數名爲
item
的push
方法,該參數必須是T類型; - 指定一個
pop
方法的返回值,該返回值將是一個T類型值。
當創建一個新單例並初始化時, 通過用一對緊隨在類型名後的尖括號裏寫出實際指定棧用到類型,創建一個Stack
實例,同創建Array
和Dictionary
一樣:
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
// 現在棧已經有4個string了
下圖將展示stackOfStrings
如何push
這四個值進棧的過程:
從棧中pop
並移除值"cuatro":
let fromTheTop = stackOfStrings.pop()
// fromTheTop is equal to "cuatro", and the stack now contains 3 strings
下圖展示瞭如何從棧中pop一個值的過程:
由於Stack
是泛型類型,所以在 Swift 中其可以用來創建任何有效類型的棧,這種方式如同Array
和Dictionary
。