泛型是Swift强大特征中的一个,许多Swift 的标准库是通过泛型来构建的。Swift 中的数组和字典就是最好的体现。[type] type可以是任何的类型。
1、泛型解决的问题:
当一个函数的功能相同,唯一的区别是传入的参数的类型不同。泛型就是一个很好的特性。将参数变为一个泛型类型的变量,就可以很好的解决这个问题。(所有的参数类型都用泛型类型来代替,从而提高了代码的复用)
2. ** 泛型函数 **
// 两个值的交换
// int 值
func swapTwoInt( a: inout Int, b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var a = 100
var b = 50
swapTwoInt(a: &a, b: &b)
print("a: \(a)")
print("b: \(b)")
a: 50
b: 100
// 字符串
func swapTwoString(a: inout String, b: inout String) {
let temporaryA = a
a = b
b = temporaryA
}
var c = "zhangsan"
var d = "lisi"
swapTwoString(a: &c, b: &d)
print("c: \(c)")
print("d: \(d)")
c: lisi
d: zhangsan
// 使用 泛型 写的交换函数
// 使用泛型函数可以交换任意类型的数据, 只要 a, b 数据类型相同就可以
func swapToValue<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
// 使用泛型函数进行转换
swapToValue(&a, &b)
swapToValue(&c, &d)
print("a: \(a)")
print("b: \(b)")
print("c: \(c)")
print("d: \(d)")
a: 50
b: 100
c: lisi
d: zhangsan
**T 的说明: **
函数的泛型版本中使用了 ** 占位类型名 **, 这里用 T 来表示 ( T : type 的第一个字母). 用来代替实际的类型名称.
- 在上述的函数中, T 没有指明是什么类型. 但是指明了 a 和 b 必须为同一个类型.
泛型函数的泛型类型只有在泛型函数调用的时候才可以知道泛型的类型是什么. - T 写在函数的后面,并用尖括号括起来 <T> 表名 T 是在函数内部定义的. swift 不会去查找 T 的实际类型.
swapToValue 的调用和平常的调用没有区别, 只有一个条件, 参数 a 和 b 的类型都是一样的.
T 所代表的类型是通过函数的参数来推断的.
类型参数
T 在函数中所表示的就是 类型参数.
类型参数指定并命名一个占位类型, 写在函数名的后面用 <> 括起来.如 <T>
可以提供多个类型参数, 写法是在尖括号中用 逗号 括起来.
<T, U, K> // 这里代表提供三个类型的占位类型
命名类型参数
大写字母开头的驼峰命名法
Dictionary<Key, Value>
Array<Element>
Key , Value, Element 都是类型参数
常用的命名有
T, U, V, K 等
类型约束
通过类型约束可以指定 类型 必须继承某个类 或者遵守某个协议
Dictionary<Key, Value>
并不是所有的类型都可以做 key
// 完整的类型声明
public struct Dictionary<Key : Hashable, Value> : Collection, ExpressibleByDictionaryLiteral { }
key 必须遵守 Hashable 协议.
只有遵守 Hashable 协议, 才可以保证 key 的唯一性.
类型约束语法
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// 这里是泛型函数的函数体部分
}
关联类型
关联类型一般用在协议.
在协议中申明一个或多个关联类型将会非常有用.
使用关键字 associatedtype
protocol Container {
// 协议中声明的关联类型
// 协议本身并不知道 ItemType 是什么类型
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
// Stack 遵守了容器协议
struct Stack<Element>: Container {
// Stack<Element> 的原始实现部分
var items = [Element]()
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
// Container 协议的实现部分
// 通过容器的实现来知道 关联类型 的具体类型是什么类型
// 这里来确认 关联类型是什么类型.
typealias ItemType = Element // 删除这一行,一样的可以工作. 类型可以推断出来
mutating func append(item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
// 通过已经存在的类型来指定关联类型的真实类型
extension Array: Container { }
where 子句
给类型参数添加强制性的约束
3. 泛型类型
Swift 允许定义泛型类型 .
自定义的泛型枚举, 结构体, 类可以用于任何类型.
struct IntStack {
var items = [Int]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
var intStack = IntStack()
// 压栈
intStack.push(item: 0)
intStack.push(item: 1)
intStack.push(item: 2)
intStack.push(item: 3)
intStack.push(item: 4)
intStack.push(item: 5)
intStack.push(item: 6)
intStack.push(item: 7)
intStack.push(item: 8)
// 弹栈
print(intStack)
intStack.pop()
print(intStack)
intStack.pop()
print(intStack)
intStack.pop()
print(intStack)
intStack.pop()
print(intStack)
intStack.pop()
print(intStack)
intStack.pop()
print(intStack)
intStack.pop()
print(intStack)
intStack.pop()
print(intStack)
intStack.pop()
// 泛型结构体
struct Stack<Element>{
var items = [Element]()
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
// 调用的时候要 指定数据类型
var tempStack = Stack<Int>()
tempStack.push(item: 0)
tempStack.push(item: 1)
tempStack.push(item: 2)
tempStack.push(item: 3)
tempStack.push(item: 4)
tempStack.push(item: 5)
print(tempStack)
tempStack.pop()
print(tempStack)
tempStack.pop()
print(tempStack)
tempStack.pop()
print(tempStack)
tempStack.pop()
print(tempStack)
tempStack.pop()
print(tempStack)
tempStack.pop()
// 调用的时候要 指定数据类型
var tempStack = Stack<Int>()
通过创建的时候指定类型. 这个结构体可以用于任何类型.
扩展泛型类型
// 泛型的扩展
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}