《swift2.0 官方教程中文版》 第2章-23泛型
import Foundation
/*泛型所解决的问题*****************************************************/ //这里是一个标准的,非泛型函数 swapTwoInts,用来交换两个Int值: func swapTwoInts(inout a: Int,inout _ b: Int) { let temporaryA = a a = b b = temporaryA }
var someInt = 3 var anotherInt = 107 swapTwoInts(&someInt,&anotherInt) print("someInt is now (someInt),and anotherInt is now (anotherInt)") // 输出 "someInt is now 107,and anotherInt is now 3"
//swapTwoInts(_:_:) 函数是非常有用的,但是它只能交换 Int 值,如果你想要交换两个 String 或者 Doubl e,就不得不写更多的函数,如 swapTwoStrings 和 swapTwoDoubles(_:_:),如同如下所示: func swapTwoStrings(inout a: String,inout _ b: String) { let temporaryA = a a = b b = temporaryA } func swapTwoDoubles(inout a: Double,inout _ b: Double) { let temporaryA = a a = b b = temporaryA } //你可能注意到 swapTwoInts 、 swapTwoStrings 和 swapTwoDoubles(_:_:) 函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是 Int 、 String 和 Double 。
//注意: 在所有三个函数中,a 和 b 的类型是一样的。如果 a 和 b 不是相同的类型,那它们俩就不能互换 值。Swift 是类型安全的语言,所以它不允许一个 String 类型的变量和一个 Double 类型的变量互相交换 值。如果一定要做,Swift 将报编译错误。
/*泛型函数*****************************************************/ func swapTwoValues<T>(inout a:T,inout _ b:T) { let temporaryA = a a = b b = temporaryA } var someInt1 = 3 var anotherInt1 = 107 swapTwoValues(&someInt1,&anotherInt1) print("someInt1 is now (someInt1),and anotherInt1 is now (anotherInt1)") // someInt 现在等于 107,anotherInt 现在等于 3
var someString = "hello" var anotherString = "world" swapTwoValues(&someString,&anotherString) print("someInt is now (someString),and anotherInt is now (anotherString)") // someString 现在等于 "world",anotherString 现在等于 "hello"
/*类型参数*****************************************************/
/*命名类型参数*****************************************************/ //如果你使用多个参数定义更复杂的泛型函数或泛型类型,那么使用更多的描述类型参数是非常有用的。例如,Swi ft 字典(Dictionary)类型有两个类型参数,一个是键,另外一个是值。如果你自己写字典,你或许会定义这两 个类型参数为 Key和 Value,用来记住它们在你的泛型代码中的作用。 //注意 请始终使用大写字母开头的驼峰式命名法(例如 T 和 Key )来给类型参数命名,以表明它们是类型的占 位符,而非类型值。
/*泛型类型*****************************************************/ 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() } } //T 定义了一个名为“某种类型T”的节点提供给后来用。这种将来类型可以在结构体的定义里任何地方表示 为“T”。在这种情况下,T 在如下三个地方被用作节点: //? 创建一个名为 items 的属性,使用空的T类型值数组对其进行初始化; //? 指定一个包含一个参数名为 item 的 push(_:) 方法,该参数必须是T类型; //? 指定一个 pop 方法的返回值,该返回值将是一个T类型值。
var stackOfStrings = Stack<String>() stackOfStrings.push("uno") stackOfStrings.push("dos") stackOfStrings.push("tres") stackOfStrings.push("cuatro") // 现在栈已经有4个string了 let fromTheTop = stackOfStrings.pop() print("(stackOfStrings)") // fromTheTop 等于 "cuatro",现在栈中还有3个string
/*扩展一个泛型类型*****************************************************/ extension Stack { var topItem: T? { return items.isEmpty ? nil : items[items.count - 1] } } //topItem 属性会返回一个 T 类型的可选值。当栈为空的时候,topItem 将会返回 nil ;当栈不为空的时候,Item 会返回 items 数组中的最后一个元素。 if let topItem = stackOfStrings.topItem { print("The top item on the stack is (topItem).") } // 输出 "The top item on the stack is tres."
/*类型约束*****************************************************/ //func someFunction<T: SomeClass,U: SomeProtocol>(someT: T,someU: U) { // // 这里是函数主体 //}
//这里有个名为 findStringIndex 的非泛型函数,该函数功能是去查找包含一给定 String 值的数组。若查找到匹配 的字符串,findStringIndex(_:_:) 函数返回该字符串在数组中的索引值( Int ),反之则返回 nil : func findStringIndex(array: [String],_ valueToFind: String) -> Int? { for(index,value) in array.enumerate() { if value == valueToFind { return index } } return nil } let strings = ["cat","dog","llama","parakeet","terrapin"] if let foundIndex = findStringIndex(strings,"llama") { print("The index of llama is (foundIndex)") } // 输出 "The index of llama is 2"
func findIndex<T:Equatable>(array:[T],_ valueToFind:T) -> Int? { for(index,value) in array.enumerate() { if value == valueToFind { return index } } return nil } let doubleIndex = findIndex([3.14159,0.1,0.25],9.3) print("索引号是(doubleIndex)") // doubleIndex is an optional Int with no value,because 9.3 is not in the array let stringIndex = findIndex(["Mike","Malcolm","Andrea"],"Andrea") print("索引号是(stringIndex)") // stringIndex is an optional Int containing a value of 2
/*关联类型*****************************************************/ protocol Container { typealias ItemType mutating func append(item: ItemType) var count: Int{ get } subscript(i: Int) -> ItemType{ get } }
struct IntStack2: Container { // IntStack的原始实现 var items = [Int]() mutating func push(item: Int) { items.append(item) } mutating func pop() -> Int { return items.removeLast() } // 遵循Container协议的实现 typealias ItemType = Int mutating func append(item: Int) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> Int { return items[i] } }
struct Stack2<T>: Container { // original Stack<T> implementation var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> T { return items[i] } }
/*Where 语句*****************************************************/ //下面的例子定义了一个名为 allItemsMatch 的泛型函数,用来检查两个Container实例是否包含相同顺序的相同 元素。如果所有的元素能够匹配,那么返回一个为 true 的 Boolean 值,反之则为 false。 func allItemsMatch<C1:Container,C2:Container where C1.ItemType == C2.ItemType,C1.ItemType: Equatable> (someContainer: C1,anotherContainer: C2) -> Bool { // 检查两个Container的元素个数是否相同 if someContainer.count != anotherContainer.count { return false } // 检查两个Container相应位置的元素彼此是否相等 for i in 0..<someContainer.count { if someContainer[i] != anotherContainer[i] { return false } } // 如果所有元素检查都相同则返回true return true }
var stackOfStrings2 = Stack2<String>() stackOfStrings2.push("uno") stackOfStrings2.push("dos") stackOfStrings2.push("tres")
var arrayOfStrings2 = ["uno","dos","tres"]
//if allItemsMatch(stackOfStrings2,arrayOfStrings2) { // print("All items match.") //} else { // print("Not all items match.") //} // 输出 "All items match." //上面的例子创建一个 Stack 单例来存储 String,然后压了三个字符串进栈。这个例子也创建了一个 Array 单 例,并初始化包含三个同栈里一样的原始字符串。即便栈和数组是不同的类型,但它们都遵循 Container 协 议,而且它们都包含同样的类型值。因此你可以调用 allItemsMatch(_:_:) 函数,用这两个容器作为它的参数。在 上面的例子中,allItemsMatch(_:_:) 函数正确的显示了这两个容器的所有元素都是相互匹配的。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |