简介
泛型代码让你能够根据自定义的需求,编写出适用于任意类型、灵活可重用的函数及类型。它能让你避免代码的重复,用一种清晰和抽象的方式来表达代码的意图。从Java1.5开始,引进了泛型,Swift和Java的泛型很类似,都很强大,学过Java的同学都知道。
Swift中的数组、字典、集合都是泛型集合,同样的Java的集合类型也是支持泛型的,可能是为了兼容,也可以不指定泛型。
泛型类型
Swift 允许你定义泛型类型。这些自定义类、结构体和枚举可以适用于任何类型。
我们看下自定义栈类型的数据结构:
struct Stack<Element> {
var items = [Element]()
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
类型约束
你可以在一个类型参数名后面放置一个类名或者协议名,并用冒号进行分隔,来定义类型约束,它们将成为类型参数列表的一部分。
看个例子:
func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
for (index, value) in array.enumerate() {
if value == valueToFind {
return index
}
}
return nil
}
任何 Equatable 类型都可以安全地使用在 findIndex(::) 函数中,因为其保证支持等式操作符。在这个函数中,定义一个 Equatable 类型约束作为类型参数定义的一部分。
关联类型
定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分将会非常有用。关联类型为协议中的某个类型提供了一个占位名(或者说别名),其代表的实际类型在协议被采纳时才会被指定。你可以通过 associatedtype 关键字来指定关联类型。
下面例子定义了一个 Container 协议,该协议定义了一个关联类型 ItemType:
protocol Container {
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
让泛型 Stack 结构体遵从 Container 协议:
struct Stack<Element>: Container {
// Stack<Element> 的原始实现部分
var items = [Element]()
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
// Container 协议的实现部分
mutating func append(item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
这一次,占位类型参数 Element 被用作 append(_:) 方法的 item 参数和下标的返回类型。Swift 可以据此推断出 Element 的类型即是 ItemType 的类型。
Where 子句
类型约束让你能够为泛型函数或泛型类型的类型参数定义一些强制要求。
下面的例子定义了一个名为 allItemsMatch 的泛型函数,用来检查两个 Container 实例是否包含相同顺序的相同元素。如果所有的元素能够匹配,那么返回 true,否则返回 false。
被检查的两个 Container 可以不是相同类型的容器(虽然它们可以相同),但它们必须拥有相同类型的元素。这个要求通过一个类型约束以及一个 where 子句来表示:
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, _ anotherContainer: C2) -> Bool {
// 检查两个容器含有相同数量的元素
if someContainer.count != anotherContainer.count {
return false
}
// 检查每一对元素是否相等
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// 所有元素都匹配,返回 true
return true
}
看了这个例子很容易明白,不用多说。有Java基础的同学,学起来应该很容易的。