swift泛型知识主要包括:泛型函数、泛型协议、泛型类型、泛型约束。
一、泛型函数。
如:一个交换两个变量值的函数。
//交换两个Int类型
func swapTwoIntValue( a: inout Int, b: inout Int) {
let tempValue = a
a = b
b = tempValue
}
如果要交换两个String类型的,就需要再写一个函数,也就是说交换每种类型都要写一个函数,比较麻烦。而使用泛型一个函数就搞定了。
//使用泛型
func swapTwoValues <T>( a: inout T, b: inout T) {
let tempValue = a
a = b
b = tempValue
}
//存在swap(_:_:)函数,可以直接使用。
二、泛型协议(关联类型)
如定义一个协议
protocol Stackable{
// 声明一个关联类型,使用associatedtype关键字
associatedtype ItemType
mutating func push(item:ItemType)
mutating func pop() -> ItemType?
}
关联类型为协议中的某个类型提供了一个占位名(或者说别名),其代表的实际类型在协议被采纳时才会被指定。你可以通过 associatedtype 关键字来指定关联类型。
使用:
struct IntStack: Stackable {
typealias ItemType = Int
var items = [Int]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int? {
if items.count == 0 {
return nil
}
return items.removeLast()
}
}
由于 Swift 的类型推断,你实际上不用在 IntStack 的定义中声明 ItemType 为 Int。因为 IntStack 符合 Stackable 协议的所有要求,Swift 只需通过 push(_:) 方法的 item 参数类型和下标返回值的类型,就可以推断出 ItemType 的具体类型。事实上,如果你在上面的代码中删除了 typealias ItemType = Int 这一行,一切仍旧可以正常工作,因为 Swift 清楚地知道 ItemType 应该是哪种类型。
三、泛型类型
如:定义一个Stack实现push、pop操作。
1、一个非泛型( Int)的栈
struct IntStack {
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
上面的 IntStack 结构体只能用于 Int 类型,如果是其他类型只能再定义另一个Stack了。
2、泛型 Stack 结构体
struct Stack1<T> {
var items = [T]()
mutating func push(_ item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
四、泛型约束
泛型约束主要分为:继承约束、协议约束、条件约束。
1、继承约束。
泛型类型必须是某个类的子类类型
格式:
func 函数名<泛型: 继承父类>(参数列表) -> 返回值 {
// 函数体,泛型类型是某个类的子类类型
}
如,有三个类,Animal、Dog、Cat,Dog、Cat继承于Animal。它们都有一个run的函数。
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")
}
}
使用:
func test() {
let dog = Dog()
animalRunPrint(animal: dog)
let cat = Cat()
animalRunPrint(animal: cat)
//传的参数需要是Animal或其子类。
}
//继承约束
func animalRunPrint<T:Animal>(animal:T) {
animal.run() // 继承了Animal类的子类都有run方法可以调用
}
2、协议约束
泛型类型必须遵循某些协议。
格式:
func 函数名<泛型: 协议>(参数列表) -> 返回值 {
// 函数体,泛型类型遵循某些协议
}
如:获取一个元素在数组里的索引。
//协议约束
func findIndex<T: Equatable>(array: [T], valueToFund: T) -> Int? {
var index = 0
for value in array {
if value == valueToFund {
return index
}
index += 1
}
return nil
}
使用:
func test() {
let doubleIndex = findIndex(array: [1.0,4.9,3.2], valueToFund: 3.0)
print("doubleIndex = \(String(describing: doubleIndex))")
}
3、条件约束
泛型类型必须满足某种条件
格式:
func 函数名<泛型1, 泛型2 where 条件>(参数列表) -> 返回值 {
// 函数体,泛型类型满足某些条件
}
如:声明一个协议Stackable,创建了一个结构体Stack,如下
protocol Stackable{
// 声明一个关联类型,使用typealias关键字
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()
}
}
使用:
func test() {
// 创建Stack结构体,泛型类型为String
var stackOne = Stack<String>()
stackOne.push(item: "hello")
stackOne.push(item: "swift")
stackOne.push(item: "world")
var stackTwo = Stack<String>()
pushItemOneToTwo(stackOne: &stackOne, stackTwo: &stackTwo)
}
//条件约束
// 添加泛型条件约束,C1和C2必须遵循Stackable协议,而且C1和C2包含的泛型类型要一致
func pushItemOneToTwo<C1: Stackable, C2: Stackable>( stackOne: inout C1, stackTwo: inout C2)
where C1.ItemType == C2.ItemType
{
// 因为C1和C2都遵循了Stackable协议,才有ItemType属性可以调用
let item = stackOne.pop()
stackTwo.push(item: item)
}












网友评论