[关闭]
@wrlqwe 2016-05-22T23:07:57.000000Z 字数 2769 阅读 1119

Swift中的泛型

Swift 泛型


泛型是现代编程语言的重要特征,相对于Obj-C,基于Swift的泛型特性,你能够写出扩展性更强、复用性更强的方法、类型,它可以让你尽可能避免重复代码,用一种清晰和抽象的方式来表达代码的意图。

泛型函数

下面是一个典型的泛型:

  1. func exchangeValue<T>(inout left: T, inout right: T) {
  2. (left, right) = (right, left)
  3. }
  4. var leftVal = 100
  5. var rightVal = 200
  6. exchangeValue(&leftVal, right: &rightVal)
  7. print("\(leftVal), \(rightVal)") // 200, 100

这个例子里,我们通过inout定义了可以改变参数值的函数, 然后利用元组,实现了值交换的逻辑。当然,他们要针对同一个泛型T的实例。

在Swift中,泛型所能做的事远远不止这些。

泛型类型

接下来,我们通过泛型特性,实现一个典型的Stack构造。

Stack是程序设计里一个典型的数据结构,它跟Array类似,但是功能上与Array并不想吐,它存储一个队列,遵循先进后出的原则存储数据。

Generics.html未知大小

除了泛型函数,Swift还允许你定义自己的泛型类型。通过自定泛型类型,我们可以很容易扩展类型的适用范围,更好地复用代码。

  1. struct Stack<T> {
  2. var items = [T]()
  3. mutating func push(item: T) {
  4. items.append(item)
  5. }
  6. mutating func pop() -> T {
  7. return items.removeLast()
  8. }
  9. }

关联类型

之前阐述的protocol里的所有类型都是确切的,Swift允许你在protocol中使用类似于泛型函数泛型类型的泛类型,这就是关联类型(Associated Types)。

  1. protocol Container {
  2. associatedtype ItemType
  3. mutating func append(item: ItemType)
  4. var count: Int { get }
  5. subscript(i: Int) -> ItemType { get }
  6. }

Container协议定义了三个任何容器必须支持的兼容要求:

这个Container协议没有指定容器中的元素是如何存储的,也没有指定容器可以存储的元素类型,但是限制了append方法的形参类型必须和subscript返回值类型一致。这种限制构成所谓的关联类型

接下来,我们为Stack实现Container协议:

  1. struct Stack<T>: Container {
  2. var items = [T]()
  3. mutating func push(item: T) {
  4. items.append(item)
  5. }
  6. mutating func pop() -> T {
  7. return items.removeLast()
  8. }
  9. mutating func append(item: T) {
  10. items.append(item)
  11. }
  12. var count: Int {
  13. return items.count
  14. }
  15. subscript(i: Int) -> T {
  16. return items[i]
  17. }
  18. }

泛型Where约束

类型约束使得Swift的泛型更加强大,但是还不够灵活。想象一个应用场景。某个函数接受两个参数,这两个参数都要求遵循Container协议,除此之外,还都要求这两个参数(集合类型)的元素类型相同,如何实现?单纯的类型约束是办不到的,好在Swift为我们带来了where语句。

where语句的目的很直接,增强了「泛型」的威力。根据我的理解,where应该属于那种约束少、灵活大的语言特性,关于它的使用想必非常繁杂。

下面举个例子引出where的应用场景。定义一个名为allItemsMatch的泛型函数,顾名思义,该函数用来检查两个Container是否包含相同顺序的相同元素,如果所有元素顺序相同且值相同,则返回true,否则返回false,如下:

  1. func allItemsMatch<
  2. C1: Container, C2: Container
  3. where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
  4. (someContainer: C1, anotherContainer: C2) -> Bool {
  5. // check that both containers contain the same number of items
  6. if someContainer.count != anotherContainer.count {
  7. return false
  8. }
  9. // check each pair of items to see if they are equivalent
  10. for i in 0..<someContainer.count {
  11. if someContainer[i] != anotherContainer[i] {
  12. return false
  13. }
  14. }
  15. // all items match, so return true
  16. return true
  17. }

泛型函数allItemsMatch头部信息告诉我们:

其中,后两部分内容定义在Where语句中,作为C1和C2的约束。

allItemsMatch(_:_:)方法用起来是这样的:

  1. var stackOfStrings = Stack<String>()
  2. stackOfStrings.push("uno")
  3. stackOfStrings.push("dos")
  4. stackOfStrings.push("tres")
  5. var arrayOfStrings = ["uno", "dos", "tres"]
  6. if allItemsMatch(stackOfStrings, arrayOfStrings) {
  7. print("All items match.")
  8. } else {
  9. print("Not all items match.")
  10. }

鸣谢: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注