从 Playgrounds 论 Swift(22): 泛型(Generics)

转载请声明出处:1、概念泛型可以让你根据需求定义适用于任何类型的灵活且可重用的函数和类型。如何命名占位类型参数?简单情况下,泛型函数或泛型类型需要指定一个占位类型,通常用一单个字母 T 来命名类型参数。复杂情况下,建议使用更多的描述类型参数,命名规则为大写字母开头的驼峰式命名法。2、为什么会有泛型以往由于功能相同、类型不同,实现两个不同类型的数据交换功能需写两个函数。现在通过泛型写一个通用函数就能实现上述通性功能。func swapTwoInts(inout a: Int, inout b: Int) {let temporaryA = aa = bb = temporaryA}func swapTwoStrings(inout a: String, inout b: String) {let temporaryA = aa = bb = temporaryA}// 泛型函数实现通性功能func swapTwoValues<T>(inout a: T, inout b: T) {let temporaryA = aa = bb = temporaryA}3、泛型函数占位符跟在函数名后面,用 <> 包含,如果有多个占位符,用(,)隔开,引用时需要在参数前加上(&)。func swapTwoValues<T>(inout a: T, inout b: T) {let temporaryA = aa = bb = temporaryA}var someInt = 3var anotherInt = 107swapTwoValues(&someInt, &anotherInt) var someString = "hello"var anotherString = "world"swapTwoValues(&someString, &anotherString)4、泛型类型(1)泛型类型的定义占位符跟在类型后面,用 <> 包含。// 定义一个 Int 类型的栈,并实现 push 和 pop 功能struct IntStack {var items = [Int]()mutating func push(item: Int) {items.append(item)}mutating func pop() -> Int {return items.removeLast()}}// 通过泛型类型可以定义一个通用类型的栈struct Stack<T> {var items = [T]()mutating func push(item: T) {items.append(item)}mutating func pop() -> T {return items.removeLast()}}var stackOfStrings = Stack<String>()stackOfStrings.push("uno")stackOfStrings.push("dos")stackOfStrings.push("tres")stackOfStrings.push("cuatro")let fromTheTop = stackOfStrings.pop()println(stackOfStrings.items)// prints "[uno, dos, tres]"println(fromTheTop)// prints "cuatro"(2)泛型类型的扩展为上述 Stack 添加一个只读计算属性,如果栈为空返回 nil,如果不为空返回最后一个数据。struct Stack<T> {var items = [T]()mutating func push(item: T) {items.append(item)}mutating func pop() -> T {return items.removeLast()}}extension Stack {var topItem: T? {return items.isEmpty ? nil : items[items.count – 1]}}var stackOfStrings = Stack<String>()stackOfStrings.push("uno")stackOfStrings.push("dos")stackOfStrings.push("tres")stackOfStrings.push("cuatro")if let topItem = stackOfStrings.topItem {println("The top item on the stack is \(topItem).")}// prints "The top item on the stack is tres."5、类型约束类型约束指一个类型参数必须继承自指定类,或者遵循一个特定的协议。例如 Dictionary 的键类型必须为可哈希的。// 泛型函数的类型约束语法func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {// function body goes here}上述语法中,第一个类型参数 T,必须是 SomeClass 子类的类型约束;第二个类型参数 U,必须遵循 SomeProtocol 协议的类型约束。// 查找一字符串数组中某个字符串的位置func findStringIndex(array: [String], valueToFind: String) -> Int? {for (index, value) in enumerate(array) {if value == valueToFind {return index}}return nil}let foundIndex = findStringIndex(["cat", "dog", "llama", "parakeet", "terrapin"], "llama")// 查找一指定类型数组中某个数据的位置func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? {for (index, value) in enumerate(array) {if value == valueToFind {return index}}return nil}let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")上述例子中使用 Equatable 对类型参数 T 进行类型约束,因为不是所有类型都可以用等式符号(==)进行比较的,所以使它遵循 Equatable 协议约束后方可使用。6、关联类型在定义一个协议时,有的时候通过关键字 typealias 指定关联类型是非常有用的。// 定义一个 Container 协议protocol Container {// 定义一个关联类型typealias ItemType// 要求该协议必须可以添加新的 item 到容器中mutating func append(item: ItemType)// 要求该协议必须可以计算容器内 items 的数量var count: Int { get }// 要求该协议必须可以通过索引值下标获取 itemsubscript(i: Int) -> ItemType { get }}// 定义一个 Int 的栈,遵循 Container 协议struct IntStack: Container {var items = [Int]()mutating func push(item: Int) {items.append(item)}mutating func pop() -> Int {return items.removeLast()}typealias ItemType = Intmutating func append(item: Int) {self.push(item)}var count: Int {return items.count}subscript(i: Int) -> Int {return items[i]}}// 定义一个通用的栈,遵循 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) {self.push(item)}var count: Int {return items.count}subscript(i: Int) -> T {return items[i]}}上述代码中 IntStack 结构体中 typealias ItemType = Int 一行如果删除仍旧正常工作,,因为 Swift 通过查找 append 方法的参数类型和下标的返回类型已经自动推断出 ItemType 类型为 Int。7、泛型中的 Where 语句where 语句使你能够要求一个关联类型遵循一个特定的协议,以及(或)那个特定的类型参数和关联类型可以是相同的。// 定义一个 Container 协议protocol Container {typealias ItemTypemutating func append(item: ItemType)var count: Int { get }subscript(i: Int) -> ItemType { get }}// 定义一个通用的栈,遵循 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) {self.push(item)}var count: Int {return items.count}subscript(i: Int) -> T {return items[i]}}// 检查是否两个 Container 实例包含具有相同顺序的相同元素func allItemsMatch< C1: Container, C2: Containerwhere 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}}return true}var stackOfStrings = Stack<String>()stackOfStrings.push("uno")stackOfStrings.push("dos")stackOfStrings.push("tres")var anotherStackOfStrings = Stack<String>()anotherStackOfStrings.push("uno")anotherStackOfStrings.push("dos")anotherStackOfStrings.push("tres")if allItemsMatch(stackOfStrings, anotherStackOfStrings) {println("All items match.")} else {println("Not all items match.")}// prints "All items match."上述示例要求了以下内容:8、结语文章最后更新时间:2015年2月9日09:54:00。欲了解更细致的请参考官方文档:

学会宽容,要有一颗宽容的爱心!

从 Playgrounds 论 Swift(22): 泛型(Generics)

相关文章:

你感兴趣的文章:

标签云: