为什么需要泛型
- 无泛型时代的"粘贴式"编程
 
            
            
              swift
              
              
            
          
          // 只能交换 Int
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temp = a
    a = b
    b = temp
}
// 复制粘贴,改个类型名
func swapTwoStrings(_ a: inout String, _ b: inout String) {
    let temp = a
    a = b
    b = temp
}
        问题:
- 代码完全一样,仅类型不同
 - 维护 N 份副本,牵一发而动全身
 
泛型函数:写一次,跑所有类型
- 语法与占位符 T
 
            
            
              swift
              
              
            
          
          // <T> 声明一个"占位符类型"
// 编译器每次调用时把 T 替换成真实类型
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}
        - 调用方式:编译器自动推断 T
 
            
            
              swift
              
              
            
          
          var x = 3, y = 5
swapTwoValues(&x, &y)          // T 被推断为 Int
var s1 = "A", s2 = "B"
swapTwoValues(&s1, &s2)        // T 被推断为 String
        要点:
- 占位符名可以是任意合法标识符,习惯单字母 
T、U、V - 同一函数签名里所有 
T必须是同一真实类型,不允许swapTwoValues(3, "hello") 
泛型类型:自定义可复用容器
- 非泛型版 Int 栈
 
            
            
              swift
              
              
            
          
          struct IntStack {
    private var items: [Int] = []
    mutating func push(_ item: Int) { items.append(item) }
    mutating func pop() -> Int { items.removeLast() }
}
        - 泛型版 Stack
 
            
            
              swift
              
              
            
          
          struct Stack<Element> {               // Element 为占位符
    private var items: [Element] = []
    mutating func push(_ item: Element) { items.append(item) }
    mutating func pop() -> Element { items.removeLast() }
}
// 用法
var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
print(intStack.pop())   // 2
var strStack = Stack<String>()
strStack.push("🍎")
strStack.push("🍌")
print(strStack.pop())   // 🍌
        类型约束:给"任意类型"划边界
- 场景:在容器里查找元素索引
 
            
            
              swift
              
              
            
          
          // 编译失败版:并非所有 T 都支持 ==
func findIndex<T>(of valueToFind: T, in array: [T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {          // ❌ 错误:T 不一定能比较
            return index
        }
    }
    return nil
}
        - 加入 Equatable 约束
 
            
            
              swift
              
              
            
          
          func findIndex<T: Equatable>(of valueToFind: T, in array: [T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {          // ✅ 现在合法
            return index
        }
    }
    return nil
}
        小结:
- 语法 
<T: SomeProtocol>或<T: SomeClass> - 可同时约束多个占位符:
<T: Equatable, U: Hashable> 
关联类型(associatedtype):协议里的"泛型"
- 定义容器协议
 
            
            
              swift
              
              
            
          
          protocol Container {
    associatedtype Item                // 占位名
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(index: Int) -> Item { get }
}
        - 让泛型 Stack 直接 conform
 
            
            
              swift
              
              
            
          
          extension Stack: Container {
    // 编译器自动推断:
    // append 参数 item 类型 = Element
    // subscript 返回值类型 = Element
    // 故 Item == Element,无需手写 typealias
}
        - 给关联类型加约束
 
            
            
              swift
              
              
            
          
          protocol EquatableContainer: Container where Item: Equatable { }
// 现在所有 Item 必须支持 ==,可直接在扩展里使用 ==/!=
        泛型 where 子句:更细粒度的约束
- 函数级 where
 
            
            
              swift
              
              
            
          
          // 检查两个容器是否完全一致(顺序、元素、数量)
func allItemsMatch<C1: Container, C2: Container>
    (_ someContainer: C1, _ anotherContainer: C2) -> Bool
    where C1.Item == C2.Item, C1.Item: Equatable
{
    if someContainer.count != anotherContainer.count { return false }
    for i in 0..<someContainer.count {
        if someContainer[i] != anotherContainer[i] { return false }
    }
    return true
}
        - 扩展级 where
 
            
            
              swift
              
              
            
          
          extension Stack where Element: Equatable {
    // 仅当元素可比较时才出现该方法
    func isTop(_ item: Element) -> Bool {
        guard let top = items.last else { return false }
        return top == item
    }
}
        - 下标也能泛型 + where
 
            
            
              swift
              
              
            
          
          extension Container {
    // 接收一组索引,返回对应元素数组
    subscript<Indices: Sequence>(indices: Indices) -> [Item]
        where Indices.Element == Int
    {
        var result: [Item] = []
        for index in indices {
            result.append(self[index])
        }
        return result
    }
}
        隐式约束与 Copyable(Swift 5.9+)
Swift 自动为泛型参数加上 Copyable 约束,以便值能被多次使用。
若你明确允许"可复制或不可复制",用前缀 ~ 抑制隐式约束:
            
            
              swift
              
              
            
          
          func consumeOnce<T>(_ x: consuming T) where T: ~Copyable {
    // x 只能被移动一次,不能再复制
}
        示例代码
把下面代码一次性粘进 Playground,逐行跑通:
            
            
              swift
              
              
            
          
          import Foundation
// 1. 通用交换
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let t = a; a = b; b = t
}
// 2. 泛型栈
struct Stack<Element> {
    private var items: [Element] = []
    mutating func push(_ e: Element) { items.append(e) }
    mutating func pop() -> Element { items.removeLast() }
}
extension Stack: Container {
    typealias Item = Element
    mutating func append(_ item: Element) { push(item) }
    var count: Int { items.count }
    subscript(i: Int) -> Element { items[i] }
}
// 3. 协议
protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(index: Int) -> Item { get }
}
// 4. 扩展约束
extension Stack where Element: Equatable {
    func isTop(_ e: Element) -> Bool { items.last == e }
}
// 5. 测试
var s = Stack<Int>()
s.push(10)
s.push(20)
print(s.isTop(20))        // true
print(s.pop())            // 20
var a: [String] = ["A","B","C"]
var b: Array<String> = ["A","B","C"]
print(allItemsMatch(a, b)) // true
        总结与实战扩展
- 
泛型 = 代码的"模板引擎"
把"类型"也当成参数,一次性书写,多处复用,减少 BUG
 - 
约束是"接口隔离"的利器
与其写长篇文档说明"请传能比较的值",不如让编译器帮你拦下来:
<T: Equatable>。 - 
关联类型让协议"带泛型"
协议不再只能定义"行为",还能定义"元素类型",使协议与泛型容器无缝衔接。
 - 
where 子句是"需求说明书"
函数、扩展、下标都能写 where,把"调用前提"写进类型系统,用不合法的状态直接编译不过,比运行时断言更早暴露问题。
 - 
实战场景举例
- JSON 解析层:写一个 
Decoder<T: Decodable>,一份代码支持所有模型 
-缓存框架:定义
Cache<Key: Hashable, Value>,Key 约束为 Hashable,Value 任意类型- 网络请求:
Request<Resp: Decodable>,响应体自动解析为任意模型 
 - JSON 解析层:写一个