什么是 Swift 中的 Generics 以及为什么需要它们
Generics(泛型编程)是 Swift 语言最强大的特性之一。它允许您编写灵活、可重用的代码,这些代码可以处理任何数据类型,同时保持严格的类型安全。您无需为 Int、String、Double 和其他类型创建单独的函数或结构体,只需编写一个通用代码,该代码会在编译时适应具体的类型。
想象一下,您需要编写一个交换两个值的函数。没有 Generics,您必须为每种类型创建重载:
func swapInts(_ a: inout Int, _ b: inout Int) { let temp = a a = b b = temp}
func swapStrings(_ a: inout String, _ b: inout String) { let temp = a a = b b = temp}使用 Generics,只需一行代码即可完成:
func swapValues<T>(_ a: inout T, _ b: inout T) { let temp = a a = b b = temp}
var x = 10, y = 20swapValues(&x, &y) // 适用于 Int
var str1 = "Hello", str2 = "World"swapValues(&str1, &str2) // 适用于 StringGenerics 的主要优势
- 类型安全: 编译器在编译阶段检查类型,消除运行时错误
- 代码重用: 一次编写的代码适用于任何类型
- 性能: Swift 中的 Generics 在编译器层面实现,不会损失执行速度
- 可读性: 减少代码重复,使代码更简洁
Generic 函数和类型参数
Generic 函数使用尖括号 <> 声明,其中指定了类型参数(通常用字母 T 表示,但可以使用任何名称)。类型参数作为一个占位符,在函数调用时会被实际类型替换。
示例:在数组中查找元素
func findIndex<T: Equatable>(of value: T, in array: [T]) -> Int? { for (index, element) in array.enumerated() { if element == value { return index } } return nil}
let numbers = [1, 5, 3, 12, 7]if let index = findIndex(of: 12, in: numbers) { print("数字 12 的索引: \\(index)") // 数字 12 的索引: 3}
let names = ["Anna", "Boris", "Victor"]if let index = findIndex(of: "Boris", in: names) { print("名字 Boris 的索引: \\(index)") // 名字 Boris 的索引: 1}注意约束条件 T: Equatable。这是一个类型约束——我们要求类型 T 支持 Equatable 协议,否则比较操作 == 将无法进行。
Generic 类型:结构体、类和枚举
Generics 不仅适用于函数,也适用于自定义类型。这使得创建通用数据容器成为可能。
创建 Generic 栈
经典示例是数据结构 Stack(栈),它可以处理任何类型:
struct Stack<Element> { private var items: [Element] = [] mutating func push(_ item: Element) { items.append(item) } @discardableResult mutating func pop() -> Element? { return items.popLast() } func peek() -> Element? { return items.last } var isEmpty: Bool { return items.isEmpty }}
// 使用示例var intStack = Stack<Int>()intStack.push(10)intStack.push(20)print(intStack.pop() ?? "") // 20
var stringStack = Stack<String>()stringStack.push("Swift")stringStack.push("Generics")print(stringStack.pop() ?? "") // GenericsGeneric 枚举
枚举也可以是