泛型(Generics)

泛型的概念:

func swapTwoInts(inout a: Int, inout _ b: Int) {
     let temporaryA = a
     a = b
     b = temporaryA
}//只能交換int類型
 var someInt = 3
 var anotherInt = 107
 swapTwoInts(&someInt, &anotherInt)
 print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
 // Prints "someInt is now 107, and anotherInt is now 3"

這里有一個(gè)方法交換int 類型的兩個(gè)變量,當(dāng)我們想要交換兩個(gè)double類型或者string類型的變量又要分別寫別的兩個(gè)函數(shù)。這時(shí)我們的泛型就展示出來(lái)它的優(yōu)勢(shì)了,泛型可以用一個(gè)方法,代表所有的類型的變量的值交換。但要求這兩個(gè)變量是相同的類型。

泛型的寫法如下:

//在方法名后面加上<T>代表T是類型參數(shù),就像數(shù)組里面的Array<Element>
 func swapTwoValues<T>(inout a: T, inout _ b: T) {
      let temporaryA = a
      a = b
      b = temporaryA
 }//可以交換任意類型,但是這兩個(gè)值的類型必須相同
 //交換int類型
 var someInt = 3
 var anotherInt = 107
 swapTwoValues(&someInt, &anotherInt)
 // someInt is now 107, and anotherInt is now 3
 //交換string類型
 var someString = "hello"
 var anotherString = "world"
 swapTwoValues(&someString, &anotherString)
 // someString is now "world", and anotherString is now "hello"

下面再舉一個(gè)例子分別定義一個(gè)只能儲(chǔ)存int類型的IntStack 結(jié)構(gòu)體棧,和可以儲(chǔ)存任意類型的Stack結(jié)構(gòu)體棧:

//只能儲(chǔ)存int類型
 struct IntStack {
     var items = [Int]()
     mutating func push(item: Int) {
          items.append(item)
     }
     mutating func pop() -> Int {
          return items.removeLast()
     }
 }
 //運(yùn)用了泛型可以儲(chǔ)存任意類型
 struct Stack<Element> {//聲明一個(gè)<Element>泛型
     var items = [Element]()
     mutating func push(item: Element) {
            items.append(item)
     }
     mutating func pop() -> Element {
            return items.removeLast()
    }
 }
 var stackOfStrings = Stack<String>()//在這里用<String>說(shuō)明儲(chǔ)存的是string類型
 stackOfStrings.push("uno")
 stackOfStrings.push("dos")
 stackOfStrings.push("tres")
 stackOfStrings.push("cuatro")
 // the stack now contains 4 strings
 let fromTheTop = stackOfStrings.pop()
 // fromTheTop is equal to "cuatro", and the stack now contains 3 strings

泛型的擴(kuò)展:

接著上邊的代碼可以對(duì)Stack 棧進(jìn)行擴(kuò)展如:給Stack 擴(kuò)展一個(gè)類型為Element的topItem屬性。

extension Stack {
     var topItem: Element? {
            return items.isEmpty ? nil : items[items.count - 1]
     }
 }
 if let topItem = stackOfStrings.topItem {
      print("The top item on the stack is \(topItem).")
 }
 // Prints "The top item on the stack is tres."

類型約束:

并不是所有的類型都能滿足函數(shù)中的泛型參數(shù),正如字典的鍵和值(Dictionary<Key, Value> )雖然都是泛型但是字典的鍵必須滿足Hashable 協(xié)議。這時(shí)候就需要對(duì)泛型進(jìn)行約束了。對(duì)泛型的約束有兩種。如下面的語(yǔ)法結(jié)構(gòu):

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
     // function body goes here
 }

約束1:<T: SomeClass>對(duì)T的約束是T必須是SomeClass的子類。
約束2:<U: SomeProtocol>對(duì)U的約束是U必須實(shí)現(xiàn)SomeProtocol這個(gè)協(xié)議。
類型約束舉例:
如下定義一個(gè)findIndex函數(shù)參數(shù)是泛型T,并且通過(guò)<T: Equatable>約束T必須實(shí)現(xiàn)Equatable這個(gè)協(xié)議。

func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
     for (index, value) in array.enumerate() {
          if value == valueToFind {
              return index
          }
     }
     return nil
 }
 let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
 // doubleIndex is an optional Int with no value, because 9.3 is not in the array
 let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
 // stringIndex is an optional Int containing a value of 2

相關(guān)類型:

相關(guān)類型跟泛型一樣,就是一個(gè)暫時(shí)不確定的,沒(méi)有指定的類型,當(dāng)聲明一個(gè)協(xié)議的時(shí)候,有時(shí)候需要定義一個(gè)或者多個(gè)相關(guān)類型來(lái)幫助協(xié)議的聲明。相關(guān)類型用associatedtype 關(guān)鍵字來(lái)標(biāo)識(shí)。

相關(guān)類型應(yīng)用舉例:

定義一個(gè)Container 協(xié)議里面有一個(gè)用associatedtype 標(biāo)識(shí)的ItemType,ItemType就是一個(gè)相關(guān)類型,只有在實(shí)現(xiàn)協(xié)議的時(shí)候才賦值確定ItemType是什么類型。但是能確定的是append方法必須有一個(gè)ItemType類型的item參數(shù),subscript方法必須返回一個(gè)ItemType 類型的參數(shù)。

protocol Container {
     associatedtype ItemType
     mutating func append(item: ItemType)
     var count: Int { get }
     subscript(i: Int) -> ItemType { get }
}
 //在這里IntStack結(jié)構(gòu)體實(shí)現(xiàn)了Container 協(xié)議
 struct IntStack: Container {
      // original IntStack implementation
      var items = [Int]()
      mutating func push(item: Int) {
          items.append(item)
      }
      mutating func pop() -> Int {
          return items.removeLast()
      }
    // conformance to the Container protocol
    //將ItemType 賦值為具體的Int型,并實(shí)現(xiàn)協(xié)議的其他方法
     typealias ItemType = Int
     mutating func append(item: Int) {
         self.push(item)
     }
     var count: Int {
        return items.count
     }
     subscript(i: Int) -> Int {
         return items[i]
     }
 }

還可以通過(guò)泛型實(shí)現(xiàn)Container 協(xié)議

struct Stack<Element>: Container {
     // original Stack<Element> implementation
     var items = [Element]()
     mutating func push(item: Element) {
          items.append(item)
     }
     mutating func pop() -> Element {
          return items.removeLast()
    }
    // 這里實(shí)現(xiàn)Container 協(xié)議的方法
    mutating func append(item: Element) {
          self.push(item)
    }
    var count: Int {
          return items.count
    }
    subscript(i: Int) -> Element {
          return items[i]
    }
 }

擴(kuò)展已經(jīng)存在的類型指定一個(gè)相關(guān)類型:

Array已經(jīng)存在了append(_:)函數(shù),count屬性,以及通過(guò)Int的參數(shù)元素返回一個(gè)subscript所有Array可以實(shí)現(xiàn)這個(gè)Container 協(xié)議并且,寫一個(gè)空的表達(dá)式,寫法如下:

extension Array: Container {}

這樣你就可以用Container 一樣用任何數(shù)組。

Where 語(yǔ)句:

接著上面的代碼,聲明一個(gè)allItemsMatch方法通過(guò)where語(yǔ)句約束C1要實(shí)現(xiàn)Equatable協(xié)議,通過(guò)自定義的Equatable協(xié)議判斷實(shí)現(xiàn)了Container協(xié)議的任意兩種類型C1和C2是否相等。判斷依據(jù)是:
1.someContainer.count != anotherContainer.count返回false。如果someContainer和anotherContainer的元素個(gè)數(shù)不相等則someContainer和anotherContainer不相等。
2.someContainer[i] != anotherContainer[i]返回false。對(duì)任意i如果someContainer[i]和anotherContainer[i]不相等則omeContainer和anotherContainer不相等。
3.如果上面兩個(gè)條件都滿足相等那么返回true則omeContainer和anotherContainer相等。

func allItemsMatch<C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> (someContainer: C1, _ anotherContainer: C2) -> Bool {
      // check that both containers contain the same number of items
     if someContainer.count != anotherContainer.count {
            return false
     }
     // check each pair of items to see if they are equivalent
     for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                   return false
            }
      }
      // all items match, so return true
      return true
 }

即使stackOfStrings屬于結(jié)構(gòu)體Stack類型,arrayOfStrings屬于數(shù)組類型,他們的類型不同,但是他們滿足上面的條件即:stackOfStrings元素個(gè)數(shù)和arrayOfStrings元素個(gè)數(shù)相同并且對(duì)于每一個(gè)stackOfStrings[i]都等于arrayOfStrings[i],所以判斷結(jié)果是stackOfStrings和arrayOfStrings相同將打印All items match.

 var stackOfStrings = Stack<String>()
 stackOfStrings.push("uno")
 stackOfStrings.push("dos")
 stackOfStrings.push("tres")
 var arrayOfStrings = ["uno", "dos", "tres"]
 if allItemsMatch(stackOfStrings, arrayOfStrings) {
         print("All items match.")
 } else {
        print("Not all items match.")
 }
 // Prints "All items match."
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容