在 Swift 中,泛型(Generics)是一种强大的特性,允许你编写具有灵活和抽象性的可重用代码。通过泛型,你可以编写函数和类型,而不需要提前确定具体的数据类型。泛型在 Swift 中被广泛用于集合类型和函数,以提供强大的灵活性和类型安全性。

以下是关于 Swift 泛型的基本信息和使用方法:

泛型函数

定义一个简单的泛型函数,可以用于任何数据类型:
// 泛型函数,交换两个值
func swapValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var x = 5
var y = 10

swapValues(&x, &y)
print("x = \(x), y = \(y)")  // 输出 "x = 10, y = 5"

在上面的例子中,<T> 表示这是一个泛型函数,而参数 a 和 b 都具有类型 T。这使得 swapValues 函数可以用于任何类型的值。

泛型类型

你还可以定义泛型类型,例如,一个泛型的栈(Stack):
// 泛型栈
struct Stack<T> {
    var items = [T]()
    
    mutating func push(_ item: T) {
        items.append(item)
    }
    
    mutating func pop() -> T? {
        return items.popLast()
    }
}

// 使用泛型栈
var stackOfInts = Stack<Int>()
stackOfInts.push(1)
stackOfInts.push(2)
stackOfInts.push(3)

print(stackOfInts.pop() ?? 0)  // 输出 3

泛型扩展

你可以对泛型类型进行扩展,为其添加额外的功能:
// 泛型栈的扩展,返回栈中的最大元素
extension Stack where T: Comparable {
    func maxElement() -> T? {
        return items.max()
    }
}

// 使用扩展的功能
print(stackOfInts.maxElement() ?? 0)  // 输出 2

在上面的例子中,Stack 被扩展以添加一个 maxElement 方法,该方法仅对元素是可比较的情况有效。

类型约束

泛型可以通过类型约束来限制可以用于泛型函数或类型的具体类型。例如,可以使用 where 关键字来添加类型约束:
// 泛型函数,只接受遵循 Equatable 协议的类型
func areEqual<T>(_ a: T, _ b: T) -> Bool where T: Equatable {
    return a == b
}

print(areEqual(5, 5))      // 输出 true
print(areEqual("hello", "world"))  // 输出 false

在上面的例子中,where T: Equatable 限制了泛型函数 areEqual 只能用于遵循 Equatable 协议的类型。

泛型协议

协议也可以是泛型的。例如,Swift 中的 Equatable 和 Comparable 就是泛型协议:
protocol Container {
    associatedtype Item
    
    mutating func addItem(_ item: Item)
    func getItem() -> Item
}

struct MyStack<T>: Container {
    var items = [T]()
    
    mutating func addItem(_ item: T) {
        items.append(item)
    }
    
    func getItem() -> T {
        return items.last!
    }
}

var stack = MyStack<Int>()
stack.addItem(1)
stack.addItem(2)
print(stack.getItem())  // 输出 2

在上面的例子中,Container 协议有一个关联类型 Item,而 MyStack 结构体通过泛型实现了这个协议。

关联类型

关联类型是协议中的一种特殊类型,表示协议中某些方法或属性的类型应该由遵循协议的类型来指定。例如:
protocol Container {
    associatedtype Item
    
    mutating func addItem(_ item: Item)
    func getItem() -> Item
}

struct MyStack<T>: Container {
    var items = [T]()
    
    mutating func addItem(_ item: T) {
        items.append(item)
    }
    
    func getItem() -> T {
        return items.last!
    }
}

var stack = MyStack<Int>()
stack.addItem(1)
stack.addItem(2)
print(stack.getItem())  // 输出 2

在上面的例子中,Container 协议有一个关联类型 Item,而 MyStack 结构体通过泛型实现了这个协议。

以上是一些关于 Swift 泛型的基本用法。泛型是 Swift 强大的特性之一,它提供了一种通用和灵活的方式来编写具有高度复用性的代码。


转载请注明出处:http://www.zyzy.cn/article/detail/14440/Swift