Swift进阶八——泛型

2021-02-15 12:43:17 浏览数 (1)

  • 之前在文章Swift基础语法(三)中有介绍过泛型,本文是对之前介绍的补充。

定义泛型函数

代码语言:javascript复制
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {    let temporatyA = a    a = b    b = temporatyA}

定义泛型类型

代码语言:javascript复制
struct Stack<Element> {    var elements = [Element]()        mutating func push(_ element: Element) {        elements.append(element)    }        mutating func pop() -> Element {        return elements.removeLast()    }}

外界使用push如下:

代码语言:javascript复制
var stackOfString = Stack<String>()stackOfString.push("uno")stackOfString.push("dos")stackOfString.push("tres")stackOfString.push("custro")

图解如下:

在上面基础上,外界使用pop如下:

代码语言:javascript复制
var stackOfString = Stack<String>()stackOfString.pop()

图解如下:

扩展泛型类型

当你扩展一个泛型类型的时候,不需要在扩展的定义中提供类型形式参数列表。原始类型定义的类型形式参数列表在扩展体里面仍然有效,并且原始类型形式参数列表名称也用于扩展类型形式参数

代码语言:javascript复制
struct Stack<Element> {    var elements = [Element]()        mutating func push(_ element: Element) {        elements.append(element)    }        mutating func pop() -> Element {        return elements.removeLast()    }}
extension Stack {    var topItem: Element? {        return elements.last    }}

Where子句

泛型函数中使用where语句

代码语言:javascript复制
protocol Container {    associatedtype ItemType        mutating func append(_ item: ItemType)    var count: Int { get }    subscript(i: Int) -> ItemType { get }}
func allItemsMatch<C1: Container, C2: Container>(someContainer: C1, anotherContainer: C2) -> Bool where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {        // 首先检查元素个数是否相等    if someContainer.count != anotherContainer.count {        return false    }        // 然后检查每一个元素是否相等    for i in 0..<someContainer.count {        if someContainer[i] != anotherContainer[i] {            return false        }    }        // 当所有都匹配成功后,返回ture    return true}

该例中的约束如下:

  • C1: Container 表示C1必须遵循Container协议
  • C2: Container 表示C2必须遵循Container协议
  • C1.ItemType == C2.ItemType 表示C1的ItemType必须要跟C2的ItemType相同
  • C1.ItemType: Equatable 表示C1的ItemType必须要遵循Equatable协议

上面?这四点意味着下面?这四点:

  • someContainer 是一个C1类型的容器
  • anotherContainer 是一个C2类型的容器
  • someContainer和anotherContainer中的元素类型是相同的
  • someContainer中的元素可以通过(!=)操作符来检查他们是否不一样

泛型类型中使用where语句

可以在扩展中使用泛型的where子句

代码语言:javascript复制
struct Stack<Element> {    var elements = [Element]()        mutating func push(_ element: Element) {        elements.append(element)    }        mutating func pop() -> Element {        return elements.removeLast()    }}
extension Stack where Element: Equatable {    func isTop(item: Element) -> Bool {        guard let lastItem = elements.last else { return false }        return item == lastItem    }}

这里的where语句表示的是:只有当Stack中的元素类型是遵循Equatable协议的时候,才会添加isTop方法。

泛型下标

在Swift中,下标也是支持泛型的。你可以在subscript后面用尖括号来写类型占位符,你还可以在下标代码块花括号前写泛型where分句

代码语言:javascript复制
protocol Container {    associatedtype ItemType        mutating func append(_ item: ItemType)    var count: Int { get }    subscript(i: Int) -> ItemType { get }}
extension Container {    subscript<Indices: Sequence>(indices: Indices) -> [ItemType] where Indices.Iterator.Element == Int {        var result = [ItemType]()        for index in indices {            result.append(self[index])        }        return result    }}
  • 尖括号中定义了泛型Indices,而Indices是遵循标准库中Sequence协议的某类型。
  • 下标接收单个形参indices。其类型是Indices。
  • 泛型where分句要求序列的遍历器必须遍历Int类型的元素,这就保证了序列中的元素类型与容器索引的类型是相同的
  • 这些限定合在一起,就意味着传入的indices形式参数是一个整数的序列

以上。

0 人点赞