泛型所解决的问题
1:这里是一个标准的,非泛型函数
func swapTwoInts(inout a : Int, inout b: Int){//这个函数使用写入读出(in-out)参数来交换a和b的值
let temp = a
a = b
b = temp
}
var someInt = 5
var anotherInt = 10
swapTwoInts(&someInt, b: &anotherInt)
print("someInt=\(someInt),anotherInt=\(anotherInt)")
//打印结果为:someInt=10,anotherInt=5
细想一下:swapTwoInts(::)函数是非常有用的,但是它只能交换Int值,如果你想要交换两个String或者Double,就不得不写更多的函数.由于函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是Int、String和Double。所以,现在泛型的作用就显示出来了.一起看一下泛型函数的操作:
2:泛型函数
/*
泛型函数可以工作于任何类型,这里是一个上面
swapTwoInts(_:_:)函数的泛型版本,用于交换两个值.
*/
func swapTwoValues<T>(inout a : T,inout b : T){
/*
类型参数:指定并命名为一个占位类型,并且紧随在函数名后面,
使用一对尖括号括起来(如<T>)。
*/
let temp = a
a = b
b = temp
}
//下面使用一下:
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, b: &anotherString)
print("someString=\(someString),anotherString=\(anotherString)")
//打印结果为:someString=world,anotherString=hello
由此可知,使用泛型操作函数的参数,那么使用非常方便,通用性非常广!
注意几个地方:
1)这个函数的泛型使用了占位类型名字(通常此情况下用字母T来表示)来代替实际类型名.占位类型名没有提示T必须是什么类型,但是它提示了a和b必须是同一类型T,而不管T表示什么类型。只有swapTwoValues(::)函数在每次调用时所传入的实际类型才能决定T所代表的类型。
2)这个泛型函数名后面跟着的占位类型名字(T)是用尖括号括起来的<>。这个尖括号告诉 Swift, 那个T是swapTwoValues(::)函数所定义的一个类型。因为T是一个占位命名类型,Swift 不会去查找命名为T的实际类型。
3)swapTwoValues(::)函数除了要求传入的两个任何类型值是同一类型外,也可以作为swapTwoInts函数被调用。每次swapTwoValues被调用,T所代表的类型值都会传给函数。
4)上面定义的函数swapTwoValues(::)是受swap函数启发而实现的。swap函数存在于 Swift 标准库,并可以在其它类中任意使用。如果你在自己代码中需要类似swapTwoValues(::)函数的功能,你可以使用已存在的交换函数swap(::)函数.
命名类型参数
在简单的情况下,泛型函数或泛型类型需要指定一个占位类型(如上面的swapTwoValues泛型函数,或一个存储单一类型的泛型集,如数组),通常用一单个字母T来命名类型参数。不过,你可以使用任何有效的标识符来作为类型参数名。
如果你使用多个参数定义更复杂的泛型函数或泛型类型,那么使用更多的描述类型参数是非常有用的。例如,Swift 字典(Dictionary)类型有两个类型参数,一个是键,另外一个是值。如果你自己写字典,你或许会定义这两个类型参数为Key和Value,用来记住它们在你的泛型代码中的作用。
注意 请始终使用大写字母开头的驼峰式命名法(例如T和Key)来给类型参数命名,以表明它们是类型的占位符,而非类型值。
类型约束
swapTwoValues(::)函数可以作用于任何类型,不过,有的时候对使用在泛型函数和泛型类型上的类型强制约束为某种特定类型是非常有用的。类型约束指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成。
类型约束语法
你可以写一个在一个类型参数名后面的类型约束,通过冒号分割,来作为类型参数链的一部分。这种作用于泛型函数的类型约束的基础语法如下所示(和泛型类型的语法相同):
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// 这里是函数主体
}
上面这个假定函数有两个类型参数。第一个类型参数T,有一个需要T必须是SomeClass子类的类型约束;第二个类型参数U,有一个需要U必须遵循SomeProtocol协议的类型约束。