//泛型(Generics)
import UIKit
/*泛型(Generics):泛型代码可以让你编写适用自定义需求以及任意类型的灵活可重用的函数和类型。它的可以让你避免重复的代码,用一种清晰和抽象的方式来表达代码的意图
类型参数:func swapTwoValues<T,B>(a:T, b:T)->T{ var c:T, var d:B ...}
1.类型参数指定并命名一个占位类型,并且紧随在函数名后面,使用一对尖括号括起来,首字母大写
2.一旦一个类型参数被指定,你可以用它来定义一个函数的参数类型,或者作为函数的返回类型,还可以用作函数主体中的注释类型。在这些情况下,类型参数会在函数调用时被实际类型所替换。
3.你可提供多个类型参数,将它们都写在尖括号中,用逗号分开
扩展一个泛型类型:
1.当你扩展一个泛型类型的时候,你并不需要在扩展的定义中提供类型参数列表
2.原始类型定义中声明的类型参数列表在扩展中可以直接使用,并且这些来自原始类型中的参数名称会被用作原始定义中类型参数的引用。
类型约束:
1.类型约束可以指定一个类型参数必须继承自指定类,或者符合一个特定的协议或协议组合。
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // 这里是泛型函数的函数体部分 }
2.可以在参数列表中通过 where 子句为关联类型定义约束。一个 where 子句能够使一个关联类型符合某个特定的协议,以及某个特定的类型参数和关联类型必须类型相同。你可以通过将 where 关键字紧跟在类型参数列表后面来定义 where 子句,where 子句后跟一个或者多个针对关联类型的约束,以及一个或多个类型参数和关联类型间的相等关系。
定义一个协议时关联类型:
1.关联类型作为协议的一部分,为某个类型提供了一个占位名(或者说别名),其代表的实际类型在协议被采纳时才会被指定。
2.你可以通过 typealias 关键字来指定关联类型。
*/
//栈:后进先出
struct Stack<Element> {
var items = [Element]()
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro") // 栈中现在有 4 个字符串
let fromTheTop = stackOfStrings.pop() // fromTheTop 的值为 "cuatro",现在栈中还有 3 个字符串
//扩展,直接使用占位类型
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
//====================
func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
for (index, value) in array.enumerate() {
if value == valueToFind { //不是所有的 Swift 类型都可以用等式符(==)进行比较,所以需要将T约束为符合Equatable协议,该协议要求任何符合该协议的类型必须实现等式符(==),从而能对符合该协议的类型的任意两个值进行比较
return index
}
}
return nil
}
//===================
protocol Container {
typealias ItemType //类型关联
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
struct IntStack: Container {
// IntStack 的原始实现部分
var items = [Int]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// Container 协议的实现部分
typealias ItemType = Int //将 Container 协议中抽象的 ItemType 类型转换为具体的 Int 类型。由于 Swift 的类型推断,你实际上不用在 IntStack 的定义中声明 ItemType 为 Int
mutating func append(item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
struct Stack1<Element>: Container {
// Stack<Element> 的原始实现部分
var items = [Element]()
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
// Container 协议的实现部分
mutating func append(item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
//=========================类型参数的约束
func allItemsMatch<C1: Container, C2: Container where 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
}
}
// 所有元素都匹配,返回 true
return true
}