泛型(Generics)

作者: 成功的失败者 | 来源:发表于2016-05-12 16:59 被阅读9次

    泛型的概念:

    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"```
    这里有一个方法交换int 类型的两个变量,当我们想要交换两个double类型或者string类型的变量又要分别写别的两个函数。这时我们的泛型就展示出来它的优势了,泛型可以用一个方法,代表所有的类型的变量的值交换。但要求这两个变量是相同的类型。
    ####泛型的写法如下:
    

    //在方法名后面加上<T>代表T是类型参数,就像数组里面的Array<Element>
    func swapTwoValues<T>(inout a: T, inout _ b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
    }//可以交换任意类型,但是这两个值的类型必须相同
    //交换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"```
    下面再举一个例子分别定义一个只能储存int类型的IntStack 结构体栈,和可以储存任意类型的Stack结构体栈:

    //只能储存int类型
     struct IntStack {
         var items = [Int]()
         mutating func push(item: Int) {
              items.append(item)
         }
         mutating func pop() -> Int {
              return items.removeLast()
         }
     }```
    

    //运用了泛型可以储存任意类型
    struct Stack<Element> {//声明一个<Element>泛型
    var items = Element
    mutating func push(item: Element) {
    items.append(item)
    }
    mutating func pop() -> Element {
    return items.removeLast()
    }
    }
    var stackOfStrings = Stack<String>()//在这里用<String>说明储存的是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```

    泛型的扩展:

    接着上边的代码可以对Stack 栈进行扩展如:给Stack 扩展一个类型为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."```
    ####类型约束:
    并不是所有的类型都能满足函数中的泛型参数,正如字典的键和值(Dictionary<Key, Value> )虽然都是泛型但是字典的键必须满足Hashable 协议。这时候就需要对泛型进行约束了。对泛型的约束有两种。如下面的语法结构:
    

    func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // function body goes here
    }```
    约束1:<T: SomeClass>对T的约束是T必须是SomeClass的子类。
    约束2:<U: SomeProtocol>对U的约束是U必须实现SomeProtocol这个协议。
    类型约束举例:
    如下定义一个findIndex函数参数是泛型T,并且通过<T: Equatable>约束T必须实现Equatable这个协议。

    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```
    ####相关类型:
    相关类型跟泛型一样,就是一个暂时不确定的,没有指定的类型,当声明一个协议的时候,有时候需要定义一个或者多个相关类型来帮助协议的声明。相关类型用associatedtype 关键字来标识。
    #####相关类型应用举例:
    定义一个Container 协议里面有一个用associatedtype 标识的ItemType,ItemType就是一个相关类型,只有在实现协议的时候才赋值确定ItemType是什么类型。但是能确定的是append方法必须有一个ItemType类型的item参数,subscript方法必须返回一个ItemType 类型的参数。
    

    protocol Container {
    associatedtype ItemType
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
    }```

     //在这里IntStack结构体实现了Container 协议
     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型,并实现协议的其他方法
         typealias ItemType = Int
         mutating func append(item: Int) {
             self.push(item)
         }
         var count: Int {
            return items.count
         }
         subscript(i: Int) -> Int {
             return items[i]
         }
     }```
    还可以通过泛型实现Container 协议
    

    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()
    }
    // 这里实现Container 协议的方法
    mutating func append(item: Element) {
    self.push(item)
    }
    var count: Int {
    return items.count
    }
    subscript(i: Int) -> Element {
    return items[i]
    }
    }```

    扩展已经存在的类型指定一个相关类型:

    Array已经存在了append(_:)函数,count属性,以及通过Int的参数元素返回一个subscript所有Array可以实现这个Container 协议并且,写一个空的表达式,写法如下:

    extension Array: Container {}```
       这样你就可以用Container 一样用任何数组。
    ####Where 语句:
    接着上面的代码,声明一个allItemsMatch方法通过where语句约束C1要实现Equatable协议,通过自定义的Equatable协议判断实现了Container协议的任意两种类型C1和C2是否相等。判断依据是:
    1.someContainer.count != anotherContainer.count返回false。如果someContainer和anotherContainer的元素个数不相等则someContainer和anotherContainer不相等。
    2.someContainer[i] != anotherContainer[i]返回false。对任意i如果someContainer[i]和anotherContainer[i]不相等则omeContainer和anotherContainer不相等。
    3.如果上面两个条件都满足相等那么返回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属于结构体Stack类型,arrayOfStrings属于数组类型,他们的类型不同,但是他们满足上面的条件即:stackOfStrings元素个数和arrayOfStrings元素个数相同并且对于每一个stackOfStrings[i]都等于arrayOfStrings[i],所以判断结果是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."```

    相关文章

      网友评论

        本文标题:泛型(Generics)

        本文链接:https://www.haomeiwen.com/subject/zkjprttx.html