泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,这种参数类型可以用在类型、函数和方法中。
一、泛型函数
下面就举个例子说明一下这个。其实好多文章都是举得这个例子,那我当然不能例外是不是,相同的例子奉上。
定义两个普通的函数,分别实现Int类型,String类型两个参数值的交换。只要是想交换一种新的类型就需要写一个方法。
func chageInt(a:inout Int, b:inout Int){
let temp = a
a = b
b = temp
}
func changeString(a:inout String, b:inout String){
let temp = a
a = b
b = temp
}
如果使用泛型,只需要一个方法就能搞定,
func change<S>( a:inout S, b:inout S){
let temp = a;
a = b;
b = temp;
}
var num1 = 1, num2=2
print("交换前===",num1,num2)
change(a: &num1, b: &num2)
print("交换后===",num1,num2)
控制台:
交换前=== 1 2
交换后=== 2 1
这就是泛型函数的基本用法了,
tips:
1、inout 代表这个变量在参数内部是可以改变的。
2、inout修饰的参数,在传值的时候需要穿参数的地址,用&修饰。
二、泛型类型
swift不但允许定义泛型函数,而且还允许定义泛型类型。这些自定义的泛型类型可以是类、结构体和枚举。
接下来举例子时刻又到了,先上代码再说有何妙用,
例子的功能是实现栈的操作,即后进先出。例子实现入栈、出斩操作。
struct Stack<T>{
//栈里边的元素
var elements = [T]()
//出栈
mutating func pop(){
elements.removeLast()
}
//入栈
mutating func push(newValue:T){
elements.append(newValue)
}
}
var myStack = Stack<String>()
myStack.push(newValue: "hello")
print("栈里边的数据为",myStack.elements)
myStack.push(newValue: "world")
print("栈里边的数据为",myStack.elements)
myStack.pop()
print("栈里边的数据为",myStack.elements)
控制台:
栈里边的数据为 ["hello"]
栈里边的数据为 ["hello", "world"]
栈里边的数据为 ["hello"]
这样无论你定义什么类型的栈,只要创建的时候把T替换为对应的类型就可以了。很方便。
当然了,如果你想要为该结构体添加扩展,只需要直接把T当做数据类型来用就可以了。
三、类型约束
默认情况下,泛型函数和泛型类型可作用于任何类型,不过,有的时候需要对泛型函数和泛型类型中的类型做一些强制约束。可以指定一个类型参数必须继承自指定类,或者符合一个特定的协议或协议组合。语法如下:
func 函数名<T:类名, U:协议名>(参数1:T, 参数2:U){}
Snip20170704_12.png
== 处程序报错是因为并不是所有的swift类型都可以用等式符(==)进行比较,例如,如果创建一个自定义的类或结构体,那么swift无法得知这个类或者结构体相等的标准是什么,所以此句代码报错,
不过,swift标准库中定义了一个Equatable协议,该协议要求其遵守者必须实现等式符(==),从而能使用==对符合该协议的类型值进行比较。所有的swift标准类都自动支持Equatable协议。因此定义泛型时可以遵守该协议。如下所示:
func findIndex<T:Equatable>(array:[T], index:T) -> Int?{
for(i, item) in array.enumerated(){
if item == index{
return i
}
}
return nil
}
print(findIndex(array: [1,2,3,4,5], index: 5) ?? "没有对应的元素")
四、关联类型
在定义协议时,有时候会对协议遵守者的元素类型有要求,此时可以在协议内部声明一个或多个关联类型。通过associatedtype关键字来指定关联类型。
为了更好的理解,接下来是例子时刻
protocol Container{
associatedtype ItemType
mutating func append(item:ItemType)
}
Container协议定义以后,协议遵守者可以通过多种方式确定关联类型的实际类型,如下:
1、普通类型定义
struct Stack:Container{
var items:[Int]
//Container 协议实现部分
typealias ItemType = String//因为下边的代码可以推断出是什么类型,所以这句话可写可不写。
mutating func append(item:String){
print(item)
}
}
var s = Stack(items: [1,2,3])
s.append(item: "1121212121212")
2、泛型类型定义
struct Stack<E>:Container{
var items:[Int]
//Container 协议实现部分
mutating func append(item:E){
print(item)
}
}
var s = Stack<String>(items: [1,2,3])
s.append(item: "1121212121212")
五、where子句
我的天我都不相信有人还会用这个东西,简直跟sql一样,好麻烦,具体用的时候再看吧。要疯了
网友评论