第二十二章 泛型
11. Contextual Where Clauses (前后关系的where子句)
我们可以写一个没用类型约束的泛型where子句作为声明的一部分。当前我们正应用于where子句的上下文中。举个例子,在泛型类型的下标里写泛型where子句或在泛型类型的扩展里写一个方法。Container结构体是一个泛型,下面的例子中指明了where子句满足哪些约束才可以在新的方法上使用。
extension Container {
func average() -> Double where Item == Int {
var sum = 0.0
for index in 0..<count {
sum += Double(self[index])
}
return sum / Double(count)
}
func endsWith(_ item: Item) -> Bool where Item: Equatable {
return count >= 1 && self[count-1] == item
}
}
let numbers = [1260, 1200, 98, 37]
print(numbers.average()) // Prints "648.75"
print(numbers.endsWith(37)) // Prints "true"
上例给Container里面添加了一个average()
方法,当Container里的物品都是整数的时候,添加 endsWith(_:)
方法当物品都是相同的情况下,这两个函数都包括一个泛型where子句,该子句将类型约束添加到来自容器原始声明的泛型Item类型参数中。
如果我们没有用前后关系的where子句,那么我们要为每一个泛型where子句各写一个扩展,上面的例子和下面的例子作用是一样的。
extension Container where Item == Int {
func average() -> Double {
var sum = 0.0
for index in 0..<count {
sum += Double(self[index])
}
return sum / Double(count)
}
}
extension Container where Item: Equatable {
func endsWith(_ item: Item) -> Bool {
return count >= 1 && self[count-1] == item
}
}
在这个版本的例子中使用前后关系的where子句,在相同的扩展中实现了verage()
和endsWith(_:)
方法,因为没一个方法的泛型where子句指出需要满足的要求,才能使该方法可用。将这些要求移动到扩展的泛型,其中子句使方法在相同情况下可用,但每个要求需要一个扩展。
12. Associated Types with a Generic Where Clause (泛型where子句的关联类型)
我们可以包括在关联类型里面包含泛型where子句,举个例子,假设我们想要写一个包含爹地的Container版本,就像swift标准库里Sequence协议那样,下面是如何用代码实现
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
func makeIterator() -> Iterator
}
在Iterator
里的泛型where子句请求迭代必须经过相同物品类型的元素作为容器中的物品。不管迭代的类型,该makeIterator()
方法提供了容器迭代的读取权。
而继承自另一个协议的协议,通过在协议的声明里包括泛型where子句给继承的关联类型添加约束,举个例子,下面的代码声明了请求Item
遵循Comparable的协议ComparableContainer
// ComparableContainer继承Container 泛型where子句请求Item遵循Comparable
protocol ComparableContainer: Container where Item: Comparable { }
13. Generic Subscripts (泛型下标)
下标也可以是泛型,并且还可以包含泛型where子句,所以我们可以在关键字subscript
后面尖括号内写占位符类型名,并且在下标体的大括号前写泛型where子句。例如:
extension Container {
// 如何写一个泛型下标
subscript<Indices: Sequence>(indices: Indices) -> [Item]
where Indices.Iterator.Element == Int {
var result = [Item]()
for index in indices {
result.append(self[index])
}
return result
}
}
给Container协议的下标添加一个采用索引顺序的下标,并且返回一个包含给出索引值的物品的数组, 如下是泛型下标的限制条件:
- 尖括号内的泛型参数
Indices
必须是遵循来自swift标准库里的Sequence协议一个类型 - 该下标采用的是一个单一的参数indices,是一个
Indices
类型的实例 - 泛型where子句要求给顺序的循环必须经过类型
Int
的所有元素。这样确保了顺序中索引和用于容器中的索引是同一个类型。
所以这三个限制条件组合在一起,意味着传入给indices的参数是一个整数顺序。