编辑代码

// 泛型约束 或者说后面跟着协议或者 继承父类
// 继承约束使用范例
// 定义一个父类,动物类
class Animal {
    // 动物都会跑
    func run() {
        print("Animal run")
    }
}

class Dog :Animal {
    override func run() {  // 重写父类方法
        print("Dog run")
    }
}

class Cat :Animal {
    override func run() {
         print("Cat run")
    }
}

// 定义泛型函数,接受一个泛型参数,要求该泛型类型必须继承Animal
// 这里的形参是 一个类
func AnimalRunPint<T:Animal>(animal:T) {
    animal.run()  // 继承了Animal类的子类都有run方法可以调用
}

AnimalRunPint(animal:Dog())   // Dog run
AnimalRunPint(animal:Cat())   // Cat run 



// 协议约束使用范例

// 定义泛型函数,为泛型添加协议约束,泛型类型必须遵循Equatable协议
// 在一个数组中 查找一个值 并返回一个位置索引
func findIndex<T: Equatable>(array: inout [T], valueToFind: inout T) -> Int? {
    var index = 0
    for value in array {
        // 因为遵循了Equatable协议,所以可以进行相等比较
        if value == valueToFind { 
            return index
        } else {
            index += 1
        }
    }
    return nil
}

// 在浮点型数组中进行查找,Double默认遵循了Equatable协议
// 重点 有 inout 关键词的形参 其实参需要加 & 号 
var array = [3.14159, 0.1, 0.25]
var valueToFind = 9.3
let doubleIndex = findIndex(array: &array, valueToFind: &valueToFind)
if let index = doubleIndex {
    print("在浮点型数组中寻找到9.3,寻找索引为\(index)")
} else {
    print("在浮点型数组中寻找不到9.3")
}

// 在字符串数组中进行查找,String默认遵循了Equatable协议
var array2 = ["Mike", "Malcolm", "Andrea"]
var valueToFind2 = "Andrea"
let stringIndex = findIndex(array: &array2, valueToFind: &valueToFind2)
if let index = stringIndex {
    print("在字符串数组中寻找到Andrea,寻找索引为\(index)")
} else {
    print("在字符串数组中寻找不到Andrea")
}


// 定义一个泛型协议,和其他泛型使用方式不同,这里泛型是以关联类型形式使用的
// 协议不要使用 protocol Stackable<ItemType> 语法来定义泛型
protocol Stackable{
    // 声明一个关联类型,使用 associatedtype 关键字
    associatedtype ItemType
    mutating func push(item:ItemType)
    mutating func pop() -> ItemType
}


struct Stack<T>:Stackable {
    var store = [T]()
    mutating func push(item:T){  // 实现协议的push方法要求
        store.append(item)
    }
    mutating func pop() -> T {   // 实现协议的pop方法要求
        return store.removeLast()
    }
}

// 创建Stack结构体,泛型类型为String
var stackOne = Stack<String>()
stackOne.push(item: "hello")
stackOne.push(item: "swift")
stackOne.push(item: "world")
let t = stackOne.pop()
print("t = \(t)") //结果:t = world

// 添加泛型条件约束,C1和C2必须遵循Stackable协议,而且C1和C2包含的泛型类型要一致
// inout 指针 直接对外面的数操作  不用这个关键词泛型会用形参当成 常量
// 可以换行
func pushItemOneToTwo<C1: Stackable, C2: Stackable>
    (stackOne: inout C1, stackTwo: inout C2)
    where C1.ItemType == C2.ItemType {
        var item = stackOne.pop()
        stackTwo.push(item: item)
    }