如果学过java就知道泛型是什么 比如说定义一个数组 var a : [Int]
Int 就是该数组的泛型 创建一个字典也是根据泛型储存内容的
var a : Dictionary <String,String>
而泛型能解决的问题 就像字典一样 他是个不确定的键值对 你定义什么类型就能存什么类型
泛型函数
下面举个例子一个函数 要将两个参数值互换
func myswap(inout a: Int,inout b: Int) { let temp = a a = b b = temp }
如上所写 只能交换int类型数据 如果要String类型呢 是不是又要另外写一份?
这里用泛型就省力了 把参数类型改成未知的一个泛型一般用 "T"
func myswap<T>(inout a: T,inout b: T) { let temp = a a = b b = temp }
语法就不多解释了 尖括号写的是泛型 形参用就可以了
这样只要满足运算符"="操作的类型就能交换
泛型类型
在类或结构中定义一个泛型类型 下面举个栗子
class Stack<Element> { var containers = [Element]() func push(e: Element) { containers.append(e) } func pop() -> Element { return containers.removeLast() } }
var data: Stack<Int> = Stack<Int>()
这个类是模仿栈的结构有push入栈与pop出栈两个方法
类中的数组在类实例化时决定
泛型扩展
扩展时,不需要再指定泛型参数(尖括号里面的内容称之为泛型参数)
extension Stack { var count: Int { return containers.count }
func aa(e:Element){ print(e) }
} var data2 = Stack<String>() data2.push("dasdf") data2.count
泛型约束
你可以写一个在一个类型参数名后面的类型约束,通过冒号分割,来作为类型参数链的一部分。这种作用于泛型函数的类型约束的基础语法如下所示(和泛型类型的语法相同):
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // function body goes here }
上面这个假定函数有两个类型参数。第一个类型参数T
,有一个需要T
必须是SomeClass
子类的类型约束;第二个类型参数U
,有一个需要U
必须遵循SomeProtocol
协议的类型约束。
用处也跟泛型函数类似 比如写一个查找数组中是否有该数 有则返回下标 没有则返回-1
func index<T:Equatable>(arr:[T],data: T) ->Int { for (m,n) in arr.enumerate() { if n == data { return m } } return -1 }
这样写也就意味着“任何T类型都遵循Equatable
协议” 如果有多个需要约束的协议则在Eqatableh
where T:类型,T:类型....
协议的关联类型修饰符 typealias
定义协议时我们无法声明泛型 所以在协议中泛型写法变了一下
protocol Containter { typealias Element mutating func push(e: Element) mutating func pop()-> Element }
实现该协议
struct MyStack: Containter{ // typealias Element = Int var containers = [Int]() mutating func push(e: Int) { containers.append(e) } mutating func pop() -> Int { return containers.removeLast() } }
实现时经过swift类型推断 实现为 Element = Int
实现后更改泛型名称也是可以的
struct Stack<Element,Com>: Containter { //按照当前的实现,下面的代码由于类型推断,可以省略 //typealias Element = E var containers = [Element]() var com=[Com]() mutating func push(e: Element) { containers.append(e) } mutating func pop() -> Element { return containers.removeLast() } }
扩展协议时的约束以及协议关联类型的使用
//定义两个协议MM,NN protocol MM { } protocol NN : MM{ } //分别实现协议MMClass,NNClass class MMClass: MM { } class NNClass: NN { } //定义f泛型协议Container protocol Container { typealias ItemType } //扩展泛型协议Container的泛型 使其受MM协议约束 extension Container where ItemType: MM { var b: Int {return 5} } //扩展泛型协议Container的泛型 使其受NN协议约束 extension Container where ItemType: NN { var b: Int {return 6} } //TestTest类实现Container协议 class TestTest: Container { typealias ItemType = MMClass //如果这里改为MMClass,那么aaaa.b输出结构是5 } class TestTest2: Container { typealias ItemType = Int //若泛型类型的值不满足任何一个协议则无法访问b属性 } let aaaa = TestTest() aaaa.b let bbbb = TestTest2() bbbb.b//报错