【IOS开发】swift的泛型使用
一、泛型的作用
类型安全:在编译时保证类型一致性
代码复用:编写可处理多种类型的通用代码
抽象能力:创建灵活且类型安全的抽象层
1. 解决代码重复问题
// 没有使用泛型
// 需要为每种类型写重复代码
func swapInts(_ a: inout Int, _ b: inout Int) {let temp = aa = bb = temp
}func swapStrings(_ a: inout String, _ b: inout String) {let temp = aa = bb = temp
}func swapDoubles(_ a: inout Double, _ b: inout Double) {let temp = aa = bb = temp
}
// 使用泛型
// 一个函数处理所有类型
func swapValues<T>(_ a: inout T, _ b: inout T) {let temp = aa = bb = temp
}// 使用示例
var a = 5, b = 10
swapValues(&a, &b)var x = "hello", y = "world"
swapValues(&x, &y)
2. 类型安全优势
// 非泛型:容易导致运行时错误
class AnyBox {var value: Anyinit(_ value: Any) { self.value = value }
}let box = AnyBox(42)
let string = box.value as? String // 需要强制转换,可能失败// 泛型:编译时类型安全
class Box<T> {var value: Tinit(_ value: T) { self.value = value }
}let intBox = Box(42)
let intValue = intBox.value // 类型明确为 Int,无需转换
二、使用
1. 基础语法
// 泛型函数
func makeArray<T>(repeating item: T, count: Int) -> [T] {return Array(repeating: item, count: count)
}// 泛型类型
struct Pair<T, U> {let first: Tlet second: U
}// 泛型协议
protocol Container {associatedtype Itemvar count: Int { get }mutating func append(_ item: Item)subscript(i: Int) -> Item { get }
}
2. 类型约束
// 基本约束
func areEqual<T: Equatable>(_ a: T, _ b: T) -> Bool {return a == b
}// 多约束
func process<T>(_ value: T) where T: Comparable, T: CustomStringConvertible {print("Processing: \(value.description)")
}// 协议关联类型约束
protocol Identifiable {associatedtype ID: Hashablevar id: ID { get }
}struct User: Identifiable {let id: Int // Int 符合 Hashable
}
3. 关联类型
protocol Store {associatedtype Itemassociatedtype Key: Hashablevar items: [Key: Item] { get set }func get(_ key: Key) -> Item?mutating func set(_ item: Item, for key: Key)
}// 实现协议时指定具体类型
class StringStore: Store {typealias Item = Stringtypealias Key = Stringvar items: [String: String] = [:]func get(_ key: String) -> String? {return items[key]}func set(_ item: String, for key: String) {items[key] = item}
}
三、注意事项
1. 性能考虑
// 泛型在编译时特化,没有运行时开销
struct Buffer<T> {private var elements: [T]// 对于值类型,编译器会为每种使用的 T 生成特化版本// 性能与手写特定类型代码相同
}// 但要注意:复杂的类型约束可能增加编译时间
func complexFunction<T>(_ value: T) where T: Collection,T.Element: Equatable,T.Index == Int {// 复杂的约束需要更多编译时间
}
2. 类型擦除模式
// 问题:协议带有关联类型时不能直接用作类型
// protocol Processor<T> { } // 错误写法// 解决方案:类型擦除
protocol Processor {associatedtype Inputassociatedtype Outputfunc process(_ input: Input) -> Output
}// 类型擦除包装器
struct AnyProcessor<Input, Output>: Processor {private let _process: (Input) -> Outputinit<P: Processor>(_ processor: P) where P.Input == Input, P.Output == Output {self._process = processor.process}func process(_ input: Input) -> Output {return _process(input)}
}// 使用
let processors: [AnyProcessor<String, Int>] = [] // 现在可以放入数组
3. 泛型继承
class BaseClass<T> {var value: Tinit(_ value: T) {self.value = value}
}// 子类可以继承泛型参数
class SubClass<T>: BaseClass<T> {func transform<U>(_ transformer: (T) -> U) -> U {return transformer(value)}
}// 或者固定泛型参数
class IntProcessor: BaseClass<Int> {func double() -> Int {return value * 2}
}
四、其他用法
1. 泛型扩展
extension Array where Element: Numeric {func sum() -> Element {return reduce(0, +)}
}extension Collection where Element: Equatable {func allEqual() -> Bool {guard let first = self.first else { return true }return allSatisfy { $0 == first }}
}// 使用
let numbers = [1, 2, 3, 4]
print(numbers.sum()) // 10let sameNumbers = [5, 5, 5, 5]
print(sameNumbers.allEqual()) // true
2. 不透明类型
// 使用 some 关键字返回具体但隐藏的类型
protocol Shape {func draw() -> String
}struct Square: Shape {func draw() -> String { return "□" }
}struct Circle: Shape {func draw() -> String { return "○" }
}// 返回具体类型,但对外隐藏具体实现
func makeShape() -> some Shape {return Square() // 编译时确定类型,但调用方只知道是 Shape
}// 与泛型结合
func makeShape<T: Shape>(_ type: T.Type) -> some Shape {return type.init()
}
3. 泛型下标
struct JSON {private var storage: [String: Any]// 泛型下标subscript<T>(key: String) -> T? {return storage[key] as? T}
}let json = JSON(storage: ["name": "John", "age": 30])
let name: String? = json["name"] // 类型明确的访问
let age: Int? = json["age"] // 自动类型推断
五、实际应用
1. 网络层泛型应用
class APIClient {func request<T: Decodable>(_ endpoint: String,method: String = "GET") async throws -> T {// 通用网络请求实现let data = try await performRequest(endpoint, method: method)return try JSONDecoder().decode(T.self, from: data)}
}// 使用
let client = APIClient()
let user: User = try await client.request("/users/1")
let posts: [Post] = try await client.request("/posts")
2. 数据持久化泛型
protocol Database {associatedtype Entity: Identifiablefunc save(_ entity: Entity)func fetch(by id: Entity.ID) -> Entity?func delete(_ entity: Entity)
}class CoreDataDatabase<Entity: Identifiable & NSManagedObject>: Database {// 具体实现...
}
