1.为什么需要泛型的使用
其实说白了很简单。就是对于方法结构相同,但是由于类型不同,而需要多次重写这些类似的方法的一种解决方案。
2.泛型的函数
看如下代码:
func swapInInts(inout a: Int, inout b: Int) { let temp = a a = b b = temp }
如上: 就是一个交换数值的方法,但是如果我现在也想对String类型,Double,Float等类型都做这样的操作,你一定想,tm写那么多类似的code真是麻烦。所以此时糊涂猫想只能用一种万能的方法解决这种类似的方法体。
泛型出现了
func swapInValues<T>(inout a:T, inout b: T) { let temp = a a = b b = temp }
现在使用起来就好赞,不经可以使用Int,String,Float等类型都可以
var a = 15 var b = 20 swapInValues(&a, &b)
3.类型参数
如上可以看到<T>
,其中类型T
是一个类型占位符,一般情况下我们是使用T来代表,但是其实是可以用任意符号表示。
4.泛型类型---实现一种较为复杂的数据结构
泛型是一种类型
实现栈的结构
非泛型
struct Stack { var items: [Int] = [Int]() mutating func push(item: Int) { items.append(item) } mutating func pop() -> Int { return items.removeLast() }
泛型
struct Stack<T> { var items: [T] = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } }
使用如下
var stackOfStrings = Stack<String>() stackOfStrings.push("uno") // push a item to stack stackOfStrings.push("dos") stackOfStrings.push("tres") stackOfStrings.push("cuatro") let resultOfPop = stackOfStrings.pop() // pop a item
5.类型约束
泛型给我门极大的自由度,那为什么要对类型进行约束呢?
泛型最初的是为了突破类型的限制,使code的复用率更高。但是并不是什么地方都适用所有类型的,因此对类型做约束就显得非常的重要。
类型约束的语法
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // function body goes here }
其中的T分别必须SomeClass类型或其子类的类型,U必须是遵循了SomeProtocol的对象。
这个概念是有些难懂,看如下一个看似没问题,但是不能通过编译的例子
func findIndex<T>(array: [T], findValue: T) -> Int? { for (index, value) in EnumerateSequence(array) { if value == findValue { return index } } return nil }
如上code,仅仅只是定义了一个泛型函数,去遍历数组中的(index, value),最后返回数组中指定的索引即可。
但是,在编译的时候,会报一个错误,译为不能确定value和findValue是否能"=="操作符来进行判断(比如自定义类型,Swift不能判断复杂的结构....)。
但是Swift给了我们很好的解决方案,只需要对类型做一个限制,让该类型实现可比较协议(Equatable)。 意味着任何T类型都遵循Equatable协议,如下所示
func findIndex<T: Equatable>(array: [T], findValue: T) -> Int? { for (index, value) in EnumerateSequence(array) { if value == findValue { return index } } return nil }
6.关联类型
当定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分是非常有用的。一个关联类型作为协议的一部分,给定了类型的一个占位名(或别名)。作用于关联类型上实际类型在协议被实现前是不需要指定的。关联类型被指定为typealias关键字。
协议定义一个关联类型
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 mutating func append(item: Int) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> Int { return items[i] } }
泛型版本的实现
struct IntStack<T>: Container { // IntStack的原始实现 var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // 遵循Container协议的实现 typealias ItemType = T //可以不用显示的声明赋值 mutating func append(item: ItemType) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> ItemType { return items[i] } }