- 前言
泛型代码让你能根据你所定义的要求写出可以用于任何类型的灵活的、可复用的函数。你可以编写出可复用、意图表达清晰、抽象的代码。
泛型是 Swift 最强大的特性之一,很多 Swift 标准库是基于泛型代码构建的。实际上,甚至你都没有意识到在语言指南中一直在使用泛型。例如,Swift的 Array和 Dictionary 类型都是泛型集合。
你可以创建一个容纳 Int 值的数组,或者容纳String 值的数组,甚至容纳任何 Swift 可以创建的其他类型的数组。同样,你可以创建一个存储任何指定类型值的字典,而且类型没有限制。 - 泛型解决的问题
下面的 swapTwoInts(.:)是一个标准的非泛型函数,用于交换两个 Int 值:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
如输入输出形式参数中描述的一样,这个函数用输入输出形式参数来交换 a和 b 的值。
swapTwoInts(.:)函数把 b原本的值给 a,把 a原本的值给 b。你可以调用这个函数来交换两个 Int 变量的值。
var someInt = 3
swapTwoInts(.:)函数很实用,但是它只能用于 Int 值。如果你想交换两个 String值,或者两个 Double值,你只能再写更多的函数,比如下面的 swapTwoStrings(.😃 和swapTwoDoubles(.😃 函数:
func swapTwoStrings(_ a: inout String, _ b: inout String) {
func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
你可能已经注意到了, swapTwoInts(.😃、 swapTwoStrings(.😃、 swapTwoDoubles(.😃 函数体是一样的。唯一的区别是它们接收值类型不同( Int、 String和 Double )。
写一个可以交换任意类型值的函数会更实用、更灵活。泛型代码让你能写出这样的函数。(下文中定义了这些函数的泛型版本。)
三个函数中, a和 b被定义为了相同的类型,这一点很重要。如果 a和 b类型不一样,不能交换它们的值。Swift 是类型安全的语言,不允许(例如)一个 String 类型的变量和一个Double 类型的变量交换值。尝试这样做会引发一个编译错误。
ps;iOS开发交流技术:欢迎你的加入,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长
- 泛型函数
泛型函数可以用于任何类型。这里是上面提到的 swapTwoInts(.😃 函数的泛型版本,叫做
swapTwoValues(.:) :
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
swapTwoValues(.:)和 swapTwoInts(.😃 函数体是一样的。但是, swapTwoValues(.😃 和swapTwoInts(.😃 的第一行有点不一样。下面是首行的对比:
func swapTwoInts(_ a: inout Int, _ b: inout Int)
泛型版本的函数用了一个占位符类型名(这里叫做 T),而不是一个实际的类型名(比如 Int 、String或 Double )。占位符类型名没有声明 T 必须是什么样的,但是它确实说了 a和 b必须都是同一个类型 T,或者说都是 T 所表示的类型。替代 T 实际使用的类型将在每次调用swapTwoValues(.😃 函数时决定。
其他的区别是泛型函数名( swapTwoValues(.😃)后面有包在尖括号( )里的占位符类型名( T)。尖括号告诉 Swift, T是一个 swapTwoValues(.:)函数定义里的占位符类型名。因为 T是一个占位符,Swift 不会查找真的叫 T 的类型。
现在,可以用调用 swapTwoInts的方式来调用 swapTwoValues(.:)函数,除此之外,可以给函数传递两个任意类型的值,只要两个实参的类型一致即可。每次调用 swapTwoValues(.😃 ,用于T 的类型会根据传入函数的值类型自动推断。
在下面的两个例子中, T分别被推断为 Int和 String :
var someInt = 3
上面定义的 swapTwoValues(
.:)函数受一个名为 swap的泛型函数启发, swap 函数是 Swift 标准库的一部分,可以用于你的应用中。如果你需要在你自己的代码中用swapTwoValues(
.:)函数的功能,可以直接用 Swift 提供的 swap(
.😃 函数,不需要自己实现。
- 类型形式参数
上面的 swapTwoValues(.:)中,占位符类型 T就是一个类型形式参数的例子。类型形式参数指定并且命名一个占位符类型,紧挨着写在函数名后面的一对尖括号里(比如 )。
点击可获取ios资料大全
一旦你指定了一个类型形式参数,你就可以用它定义一个函数形式参数(比如swapTwoValues(.:)函数中的形式参数 a和 b )的类型,或者用它做函数返回值类型,或者做函数体中类型标注。在不同情况下,用调用函数时的实际类型来替换类型形式参数。(上面的swapTwoValues(.😃 例子中,第一次调用函数的时候用 Int替换了 T,第二次调用是用 String替换的。)
你可以通过在尖括号里写多个用逗号隔开的类型形式参数名,来提供更多类型形式参数。 - 命名类型形式参数
大多数情况下,类型形式参数的名字要有描述性,比如 Dictionary<Key, Value>中的 Key 和Value ,借此告知读者类型形式参数和泛型类型、泛型用到的函数之间的关系。但是,他们之间的关系没有意义时,一般按惯例用单个字母命名,比如 T 、U、 V ,比如上面的swapTwoValues(.:)函数中的 T 。
类型形式参数永远用大写开头的驼峰命名法(比如T和MyTypeParameter)命名,以指明它们是一个类型的占位符,不是一个值。
- 泛型类型
除了泛型函数,Swift允许你定义自己的泛