Swift泛型与协议扩展深度解析
立即解锁
发布时间: 2025-09-12 01:52:38 阅读量: 9 订阅数: 32 AIGC 


Swift编程实战精要
### Swift 泛型与协议扩展深度解析
#### 1. 泛型中 `where` 子句的类型约束
在 Swift 里,`where` 关键字功能强大,它不仅能在循环或 `switch` 语句里施加约束,还能在函数声明时对泛型参数或返回类型进一步约束。下面是一个给 `Stack<Element>` 添加方法的例子,该方法可把数组中的每个元素压入栈中:
```swift
struct Stack<Element>: Sequence {
// 其他代码...
mutating func pushAll(_ array: [Element]) {
for item in array {
self.push(item)
}
}
}
// 使用示例
for value in myStack {
print("for-in loop: got \(value)")
}
myStack.pushAll([1, 2, 3])
for value in myStack {
print("after pushing: got \(value)")
}
```
不过,`pushAll(_:)` 方法虽有用,但通用性欠佳。因为任何符合 `Sequence` 协议的类型都能用于 `for-in` 循环,所以该方法不应局限于数组,而应能接受任何序列,像同样符合 `Sequence` 协议的 `Stack` 也可。
但首次尝试修改会在调用 `self.push(_:)` 时产生编译时类型错误:
```swift
struct Stack<Element>: Sequence {
// 其他代码...
mutating func pushAll<S: Sequence>(_ sequence: S) {
for item in sequence {
self.push(item)
}
}
}
```
这里把 `pushAll(_:)` 方法泛型化,用占位类型 `S` 表示符合 `Sequence` 协议的类型,虽能保证可用 `for-in` 循环遍历,但还不够。要把序列中的元素压入栈,需确保序列元素类型与栈元素类型匹配,即添加约束:序列 `S` 产生的元素类型为 `Element`。Swift 借助 `where` 子句支持此类约束:
```swift
struct Stack<Element>: Sequence {
// 其他代码...
mutating func pushAll<S: Sequence>(_ sequence: S) where S.Element == Element {
for item in sequence {
self.push(item)
}
}
}
```
此时,占位类型 `S` 要符合 `Sequence` 协议且满足 `where` 子句要求。`S.Element` 指序列 `S` 关联的 `Element` 类型,约束 `S.Element == Element` 要求 `Element` 关联类型的具体类型与栈的 `Element` 占位类型具体类型匹配。
下面是使用示例:
```swift
var myOtherStack = Stack<Int>()
myOtherStack.pushAll([1, 2, 3])
myStack.pushAll(myOtherStack)
for value in myStack {
print("after pushing items onto stack, got \(value)")
}
```
需注意,若协议有关联类型,当前不能把该协议用作变量或函数声明中的类型。例如,`Sequence` 有关联类型 `Element`,以下代码无法编译:
```swift
func printElements(from sequence: Sequence) {
for item in sequence {
print(item)
}
}
```
不过,可把协议用作泛型类型约束:
```swift
func printElements<S: Sequence>(from sequence: S) {
for element in sequence {
print(element)
}
}
```
#### 2. 泛型组合与不透明类型
泛型数据结构可通过协议相互组合,构建能优雅描述复杂概念的类型系统。例如,字典数组的组合类型可能是 `Array<Dictionary<String,Int>>`。有时,我们想隐藏组合的一些实现细节。
下面以餐厅里饥肠辘辘的人点烤面包为例。先定义 `Food` 协议和符合该协议的食物:
```swift
protocol Food {
var menuListing: String { get }
}
struct Bread: Food {
var kind = "sourdough"
var menuListing: String {
"\(kind) bread"
}
}
func eat<T: Food>(_ food: T) {
print("I sure love \(food.menuListing).")
}
eat(Bread())
```
接着定义餐厅结构体及嵌套结构体,用于定义餐厅可能制作的食物的准备方式:
```swift
struct Restaurant {
struct SlicedFood<Ingredient: Food>: Food {
var food: Ingredient
var menuListing: String {
"a slice of \(food.menuListing)"
}
}
struct CookedFood<Ingredient: Food>: Food {
var food: Ingredient
var menuListing: String {
"\(food.menuListing), cooked to perfection"
}
}
func makeSlicedBread() -> SlicedFood<Bread> {
return SlicedFood(food: Bread())
}
func makeToast() -> Coo
```
0
0
复制全文
相关推荐









