@wrlqwe
2016-05-22T23:07:57.000000Z
字数 2769
阅读 1119
Swift
泛型
泛型是现代编程语言的重要特征,相对于Obj-C,基于Swift的泛型特性,你能够写出扩展性更强、复用性更强的方法、类型,它可以让你尽可能避免重复代码,用一种清晰和抽象的方式来表达代码的意图。
下面是一个典型的泛型:
func exchangeValue<T>(inout left: T, inout right: T) {
(left, right) = (right, left)
}
var leftVal = 100
var rightVal = 200
exchangeValue(&leftVal, right: &rightVal)
print("\(leftVal), \(rightVal)") // 200, 100
这个例子里,我们通过inout定义了可以改变参数值的函数, 然后利用元组,实现了值交换的逻辑。当然,他们要针对同一个泛型T的实例。
在Swift中,泛型所能做的事远远不止这些。
接下来,我们通过泛型特性,实现一个典型的Stack构造。
Stack是程序设计里一个典型的数据结构,它跟Array类似,但是功能上与Array并不想吐,它存储一个队列,遵循先进后出的原则存储数据。
↓
除了泛型函数
,Swift还允许你定义自己的泛型类型
。通过自定泛型类型,我们可以很容易扩展类型的适用范围,更好地复用代码。
struct Stack<T> {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
之前阐述的protocol
里的所有类型都是确切的,Swift允许你在protocol中使用类似于泛型函数
、泛型类型
的泛类型,这就是关联类型
(Associated Types)。
protocol Container {
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
Container协议定义了三个任何容器必须支持的兼容要求:
这个Container协议没有指定容器中的元素是如何存储的,也没有指定容器可以存储的元素类型,但是限制了append方法的形参类型必须和subscript返回值类型一致。这种限制构成所谓的关联类型
。
接下来,我们为Stack实现Container协议:
struct Stack<T>: Container {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
mutating func append(item: T) {
items.append(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
类型约束
使得Swift的泛型更加强大,但是还不够灵活。想象一个应用场景。某个函数接受两个参数,这两个参数都要求遵循Container协议,除此之外,还都要求这两个参数(集合类型)的元素类型相同,如何实现?单纯的类型约束
是办不到的,好在Swift为我们带来了where语句。
where语句的目的很直接,增强了「泛型」的威力。根据我的理解,where应该属于那种约束少、灵活大的语言特性,关于它的使用想必非常繁杂。
下面举个例子引出where的应用场景。定义一个名为allItemsMatch的泛型函数,顾名思义,该函数用来检查两个Container是否包含相同顺序的相同元素,如果所有元素顺序相同且值相同,则返回true,否则返回false,如下:
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, anotherContainer: C2) -> Bool {
// check that both containers contain the same number of items
if someContainer.count != anotherContainer.count {
return false
}
// check each pair of items to see if they are equivalent
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// all items match, so return true
return true
}
泛型函数allItemsMatch头部信息告诉我们:
其中,后两部分内容定义在Where语句中,作为C1和C2的约束。
allItemsMatch(_:_:)
方法用起来是这样的:
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
if allItemsMatch(stackOfStrings, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}