Swift中的泛型:初学者指南——为什么需要它们以及如何使用

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Swift中的泛型是什么以及为什么需要它们

\n\n

想象一下,你正在编写一个交换两个数字的函数。然后你又需要一个用于字符串的相同函数。接着还需要一个用于日期的。如果没有泛型,你将不得不编写三个相同的函数,只是数据类型不同。这违反了DRY(不要重复自己)原则,并使代码变得臃肿。

\n\n

泛型是Swift中一种强大的机制,它允许你编写灵活、可重用的代码,适用于任何数据类型。你不需要指定具体类型,而是使用一个占位符,在调用函数或创建结构时,该占位符会被实际类型替换。

\n\n

在本文中,我们将探讨泛型在Swift中是如何工作的,并通过实际示例展示如何在iOS开发中使用它们。

\n\n

1. 泛型基础:函数和类型

\n\n

让我们从一个简单的例子开始。编写一个交换两个值的函数:

\n\n
// 没有泛型——需要为每种类型单独编写
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
}

// 使用泛型——一个函数适用于所有类型
func swapValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var x = 10, y = 20
swapValues(&x, &y) // 适用于Int
print("x: \\(x), y: \\(y)") // x: 20, y: 10

var str1 = "Hello", str2 = "World"
swapValues(&str1, &str2) // 适用于String
print("str1: \\(str1), str2: \\(str2)") // str1: World, str2: Hello
\n\n

这里的<T>是一个通用类型参数。字母T只是一个约定(来自Type一词),你可以使用任何名称:<Element>、<ValueType>等。

\n\n

泛型不仅适用于函数,也适用于类型。考虑一个简单的容器结构:

\n\n
// 用于存储单个值的泛型结构
struct Box<T> {
    let value: T
    
    init(_ value: T) {
        self.value = value
    }
}

let intBox = Box(42)        // 类型为 Box<Int>
let stringBox = Box("Swift") // 类型为 Box<String>
let arrayBox = Box([1, 2, 3]) // 类型为 Box<[Int]>

print(intBox.value)  // 42
print(stringBox.value) // Swift
\n\n

Swift编译器会根据传入的值自动确定T的类型。这被称为类型推断。

\n\n

2. 类型约束

\n\n

有时你需要限制哪些类型可以与你的泛型一起使用。例如,你想编写一个在数组中查找最大值的函数。但>运算符并不适用于所有类型——只适用于那些遵循Comparable协议的类型。

\n\n
// 约束:T必须遵循Comparable协议
func findMax<T: Comparable>(in array: [T]) -> T? {
    guard !array.isEmpty else { return nil }
    
    var maxValue = array[0]
    for element in array {
        if element > maxValue {
            maxValue = element
        }
    }
    return maxValue
}

let numbers = [3, 7, 1, 9, 5]
print(findMax(in: numbers) ?? "No max") // 9

let words = ["apple", "zebra", "banana"]
print(findMax(in: words) ?? "No max") // "zebra" (按字母顺序)
\n\n

语法<T: Comparable>的意思是:“类型T必须遵循Comparable协议”。你可以通过逗号添加多个约束,或者使用where来实现更复杂的条件:

\n\n
// 通过where添加多个约束
func process<T>(_ value: T) where T: Numeric, T: Comparable {
    if value > 0 {
        print("正数")
    }
}

博客

书籍推荐