通用代码使您能够根据您定义的要求编写可以使用任何类型的灵活,可重用的函数和类型。您可以编写避免重复的代码,并以清晰,抽象的方式表达其意图。

泛型是Swift最强大的功能之一,Swift标准库的大部分内容都是使用通用代码构建的。

import Foundation

//泛型函数
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let tmp = a
    a = b
    b = tmp
}

var a = 1, b = 2
print("\(a)====\(b)")
swapTwoValues(&a, &b)
print("\(a)====\(b)")

//泛型类型(泛型类,泛型结构体,泛型枚举),听起来挺高大上,其实就是给自定义类加个泛型
struct Stack<Element> {
    var items: [Element] = []
    mutating func push(_ item: Element) {
        items.append(item)
    }
    
    mutating func pop() -> Element {
        return items.removeLast()
    }
}
//扩展泛型类型
extension Stack {
    var topItem: Element? {
        return items.isEmpty ? nil : items[items.count - 1]
    }
}

var strings = Stack<String>()
strings.push("hello")
print(strings.topItem)
print(strings.pop())

//泛型约束(不限于泛型类型,除了泛型类型就是TM的泛型函数)
//泛型约束不能省略,如果省略value == v就不能运行了,没法玩了.
//泛型约束必须是特定类继承,或符合特定协议或协议组合
//这里Equable不能被替换为String,因为String是结构体,不能被继承.Int, Bool, Double, anything else...
//返回值不能用泛型,🙂because the type to use for T is inferred from the types of values passed to the function.
// (因为类型都是从传递给函数的值的类型推断出来的),除非再传一个参数,类似:
// func findIndex1<T: Equatable, S: SignedInteger>(of value: T,in array: [T], _ type: S) -> S?
// 告诉一下Swift,接下来会发生什么,不然Swift心里会发慌...
func findIndex1<T: Equatable>(of value: T,in array: [T]) -> Int? {
    for (i, v) in array.enumerated() {
        if value == v {
            return i
        }
    }
    return nil
}

let arr = ["a", "b", "c", "d", "e"]
let index = findIndex1(of: "a", in: arr)
print(index)


//关联类型
//协议中的泛型,实现具体类型的时候,由自己指定泛型类型为某种具体类型.
protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}

//这里typealias item不能等于协议,例如typealias Item = Equatable
//这样Swift就不知道`EquableStack`应该怎么分配内存了有木有...,谁TM知道`EquableStack`实现了几个协议
//脚踏了几只船?
//typealias Item = Int删掉也可以,可以通过append,推断出Item类型
struct IntStack: Container {
    
    mutating func push(_ item: Item) {
        items.append(item)
    }
    
    mutating func pop() -> Item {
        return items.removeLast()
    }
    
    typealias Item = Int
    var items: [Item] = []
    mutating func append(_ item: Item) {
        items.append(item)
    }
    var count: Int {
        return items.count
    }
    
    subscript(i: Int) -> Item {
        return items[i]
    }
}

//上面的Stack可以写作下面方式
//因为通过append可以知道Element为Item的具体类型,所以typealias可以省略
//又因为Stack1是泛型类型,Element创建实例对象时具体指出,所以,一下代码完全正确.
//可以写typealias Item = Element, 然后Element跟Item可以互相交叉替换🙂
struct Stack1<Element>: Container {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }

    mutating func pop() -> Element {
        return items.removeLast()
    }
    //conformance to the Container
    mutating func append(_ item: Element) {
        push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}

var strings1 = Stack1<String>()
strings.push("hello")
print(strings.topItem)
print(strings.pop())

//扩展现有类型以指定关联类型
//array 中有append用来推断具体类型,并且有count,有下标
//所以以后完全可以使用Array作为Container
//但是typealias Container = Array也是不错的
extension Array: Container {}

//将约束添加到关联类型
//如果这样定义,得像下面这样搞
//struct Stack1<Element: Equatable>: Container
protocol Container1 {
    associatedtype Item: Equatable
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}

//在关联类型的约束中使用协议
//这个JB关系有点乱,有木有...
//儿子有一个家,爹有一个家,儿子从爹那继承过来的家跟自己成立的家必须是一个家,不能搞分家...
//大概就是这样了....
protocol SuffixableContainer: Container {
    associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
    func suffix(_ size: Int) -> Suffix
}

extension Stack1: SuffixableContainer {
    func suffix(_ size: Int) -> Stack1 {
        var result = Stack1()
        //max是用来防止程序崩溃的,🙂
        for index in max((count-size), 0)..<count {
            result.append(self[index])
        }
        return result
    }
    // Inferred that Suffix is Stack.
}

var stackOfInts = Stack1<Int>()
stackOfInts.append(10)
stackOfInts.append(20)
stackOfInts.append(30)
let suffix = stackOfInts.suffix(3)

//Generic Where Clauses(通用条款)
//泛型条件约束吧... where

func allItemsMatch<C1: Container, C2: Container>(_ someContainer: C1, _ anotherContainer: C2) -> Bool where C1.Item == C2.Item, C1.Item: Equatable {
    // 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're equivalent.
    for i in 0..<someContainer.count {
        if someContainer[i] != anotherContainer[i] {
            return false
        }
    }
    // All items match, so return true.
    return true
}

var stackOfStrings = Stack1<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.")
}

extension Stack1 where Element: Equatable {
    func isTop(_ item: Element) -> Bool {
        guard let last = items.last else {
            return false
        }
        return item == last
    }
}
//如果将没有遵守Equatable用于该方法,会报错
if stackOfStrings.isTop("tres") {
    print("Top element is tres.")
} else {
    print("Top element is something else.")
}

//上面where扩展类型,下面where扩展协议,这TM就比较6了...
extension Container where Item: Equatable {
    func startsWith(_ item: Item) -> Bool {
        return count >= 1 && self[0] == item
    }
}
if [9, 9, 9].startsWith(42) {
    print("Starts with 42.")
} else {
    print("Starts with something else.")
}

//Item是特定类型的where子句
extension Container where Item == Double {
    func average() -> Double {
        var sum = 0.0
        for index in 0..<count {
            sum += self[index]
        }
        return sum / Double(count)
    }
}
print([1260.0, 1200.0, 98.6, 37.0].average())


//关联类型和泛型子句
protocol Container2 {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
    
    associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
    
    func makeIterator() -> Iterator
}

protocol ComparableContainer: Container2 where Item: Comparable {}

//泛型下标
extension Container2 {
    subscript<Indices: Sequence>(indices: Indices) -> [Item]
        where Indices.Iterator.Element == Int {
            var result = [Item]()
            for index in indices {
                result.append(self[index])
            }
            return result
    }
}

真是烧脑的玩意......

--EOF--