Swift學習筆記十九之泛型

1、泛型:使用泛型能更清晰更簡潔的表達代碼意圖

// 泛型所解決的問題
func swapTwoInts(a: inout Int, _ b: inout Int) { // 交換兩個Int的值
let temp = a
a = b
b = temp
}
var someInt = 3
var anotherInt = 5
swapTwoInts(a: &someInt, &anotherInt)

// 但如果想交換String Double類型的數該怎樣做呢?再寫兩個函數?

2、泛型函數:在函數名后面添加<T>,表示T是函數定義的占位類型;只要前后一致,別的字母也可以

func swapTwoValues<T>(a: inout T, _ b: inout T) { // 用T來替代實際類型,a和b是同一類型T
let temp = a
a = b
b = temp
}
swapTwoValues(a: &someInt, &anotherInt) // 在調用函數時,根據實際類型推斷出T的類型

var StringA = "A"
var StringB = "B"
swapTwoValues(a: &StringA, &StringB) // 只要傳入任何相同的類型都可以
print("StringA:(StringA),StringB:(StringB)") // StringA:B,StringB:A

3、類型參數
// 在上面的例子中占位類型T就是一個類型參數.
// 類型參數可以在函數名后面加一個占位類型, 并用尖括號括起來.例如< T >
// 類型參數設定后,就可以當做函數的參數類型使用了,可以是參數類型也可以是返回類型
// 當函數被調用的時候,類型參數會被轉化為實際類型
// 類型參數可以有多個,可以寫在尖括號中,用逗號隔開
// 通常使用單個字母T U V來命名類型參數,但也可以是以大寫字母開頭的字符串

4、泛型類型:能夠讓自定義類、結構體、和枚舉適用于任何類型,類似于Array和Dictionary

struct Stack<Element> { // 模擬棧的操作過程的泛型集合類型
var items = Element // 使用Element為空數組進行初始化
mutating func push(item: Element) { // push的參數類型是Element
items.append(item)
}
mutating func pop() -> Element { // pop的返回值類型是Element類型
return items.removeLast()
}
}
var stackOfStrings = Stack<String>() // 在尖括號中寫出棧中需要存儲的數據類型
stackOfStrings.push(item: "A")
stackOfStrings.push(item: "B")
stackOfStrings.push(item: "C")
let fromTheTop = stackOfStrings.pop()
print(stackOfStrings.items) // ["A", "B"]

5、泛型類型的擴展:原類型中的類型參數在擴展中可以直接使用

extension Stack {
var topItem: Element? { // 返回棧頂元素的只讀計算屬性
return items.isEmpty ? nil : items[items.count - 1]
}
}
if let topItem = stackOfStrings.topItem {
print("topItem:(topItem)") // topItem:B
}

6、類型約束:swapTwoValues(::) 和Stack適用于任何類型,但有時我們需要對類型進行一些約束,這些約束可以是類型參數必須繼承指定類,或者符合特定的協議或協議組合

class SomeClass {}
protocol SomeProtocol {}
// T的類型參數必須是SomeClass的子類,U的類型參數必須遵守SomeProtocol協議
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // 類型約束語法
}

// 根據字符串查找在數組中的索引
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
// 為T增加一個Equatable協議,遵循該協議的類型必須實現等式符和不等符號.才可以對兩個類型進行比較
if value == valueToFind {
return index
}
}
return nil
}

let doubleIndex = findIndex(of: 5.0, in: [3.2, 1.0, 5.0, 5,6]) // 2
let stringIndex = findIndex(of: "O", in: ["V", "D", "E", "O"]) // 3

7、類型的關聯:關聯類型為協議中某個類型提供別名
protocol Container { // 定義一個Container協議
associatedtype ItemType // 通過associatedtype關鍵詞來定義一個關聯類型
mutating func append(item: ItemType) // 添加一個新的元素到容器里
var count: Int { get } // 獲取容器中的元素個數
subscript(i: Int) -> ItemType { get } // 通過索引獲取容器中的元素
}

struct NewStack<Element>: Container {
var items = Element
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
mutating func append(item: Element) {
self.push(item: item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element { // swift會自動推斷Element就是ItemType類型
return items[i] // 不需要再去指定ItemType類型為Element類型
}
}
8、where子句:為泛型的類型參數做一些約束

protocol Container { // 定義一個Container協議
associatedtype ItemType // 通過associatedtype關鍵詞來定義一個關聯類型
mutating func append(item: ItemType) // 添加一個新的元素到容器里
var count: Int { get } // 獲取容器中的元素個數
subscript(i: Int) -> ItemType { get } // 通過索引獲取容器中的元素
}

struct NewStack<Element>: Container {
var items = Element
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
mutating func append(item: Element) {
self.push(item: item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element { // swift會自動推斷Element就是ItemType類型
return items[i] // 不需要再去指定ItemType類型為Element類型
}
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 136.泛型 泛型代碼讓你可以寫出靈活,可重用的函數和類型,它們可以使用任何類型,受你定義的需求的約束。你可以寫出...
    無灃閱讀 1,513評論 0 4
  • Swift 提供了泛型讓你寫出靈活且可重用的函數和類型。Swift 標準庫是通過泛型代碼構建出來的。Swift 的...
    零度_不結冰閱讀 421評論 0 0
  • 泛型代碼可以確保你寫出靈活的,可重用的函數和定義出任何你所確定好的需求的類型。你的可以寫出避免重復的代碼,并且用一...
    iOS_Developer閱讀 813評論 0 0
  • SwiftDay011.MySwiftimport UIKitprintln("Hello Swift!")var...
    smile麗語閱讀 3,857評論 0 6
  • 優惠券馬上就結束了呢,款式真心美
    南雅麻麻閱讀 268評論 0 0