泛型同意你定义一个宽松、可重用的函数或者类型。使用泛型能够避免代码的反复。也能以更清楚和抽象的方式来表达程序的意图。
泛型是Swift语言提供的强大功能之中的一个,Swift提供的很多标准库都使用了泛型来创建,如Swift提供的数组和词典类型。
通过使用泛型,你能使用一个数组和词典来包括和存储不论什么类型的元素。
1.1 泛型函数
使用Swift语言你能定义一个能够工作于随意类型的泛型函数。从而不必为每种类型都定义一个具有同样功能的函数,这样就能够大大降低代码的反复。
如对一个实现随意类型值交换(swap)的函数,能够在Swift语言中定义一个以下的泛型函数。
func swap<T>(inout a:T,inout b:T) {
let temporaryA =a
a =b
b =temporaryA
}
以上语法定义了一个实现随意类型值交换的通用版本号函数,也称为泛型函数。
定义泛型函数的语法为:定义一个通用函数名字及其后面跟着的一个闭合的三角括号<>,三角括号里包括一个字母T(能够是随意有效的标识),称为类型參数,用来指代该泛型函数定义中要使用到的类型的占位(如作为泛型函数中的输入參数和返回类型的占位)。泛型函数使用该类型參数来取代实际的类型名(能够是Int,String, 或Double等)。
类型參数使用的实际类型在每次泛型函数调用时由Swift语言依据传送给泛型函数的值的类型推定确定。例如以下样例所看到的。T被相应判断为Int和String类型。
var someInt =3
var anotherInt =107
swap(&someInt, &anotherInt)
var someString ="hello"
var anotherString ="world"
swapTwoValues(&someString, &anotherString)
类型參数用来定义泛泛型函数中參数的类型和返回类型,以及作为泛型函数体内的类型凝视。
一个泛型函数中能够提供多个类型參数,每一个类型參数在三角括号里以逗号切割。
1.2 泛型类型
与Array和Dictionary实现机制相似, Swift也同意用户定义一个能工作于随意类型的泛型类型(泛型类、泛型结构、泛型枚举)。
例如以下定义了一个能够使用随意类型的一个堆栈类。
structStack<T> {
var items =T[]()
mutating fund push(item:T) {
items.append(item)
}
mutating func pop() ->T {
return items.removeLast()
}
}
与泛型函数相似,也在跟着定义的泛型类型名字后面的三角括号内定义泛型类型用到的占位类型參数。
如上例所看到的,占位类型參数在泛型类型定义中能够用作泛型类型中的属性类型的占位。也可作为泛型类型中方法、下标方法用到的參数或返回类型的占位。
占位类型參数的实际类型在泛型类型使用时使用初始化语法指定,例如以下使用上面定义泛型类型定义了一个实际类型(字符串类型)的堆栈,泛型类型的类型參数的实际类型(String)在类型名Stack后面的三角括号里指定。
var stackOfStrings = Stack<String>()
stackOfStrings.push(“uno")
let fromTheTop =stackOfStrings.pop()
1.3 类型限制
在泛型函数和泛型类型定义中,有时须要对使用到的类型施加一些进一步的类型限制。
如在Swift语言的词典类型中要求词典的键值必须保持唯一。因此Swift语言对词典的键值类型施加的类型限制是键值类型必须符合 Hashable协议(Hashable协议是Swift标准库中定义的一种特定协议,全部的Swift基本类型默认都是符合Hashable协议的,因此都是可hashable的)。
类型限制语法:
与函数參数列表的类型定义相似:在类型參数名后面放一个类或协议来规定类型參数要遵从的类型限制。两者之间以分号切割。
例如以下是一个带类型限制的泛型函数的语法:
func someFunction<T:SomeClass,U:SomeProtocol>(someT:T,someU:U) {
// function body goes here
}
该泛型函数带有两个类型參数。分别以T和U代表,T的类型限制是T必须是SomeClass类型,U的类型限制是U必须符合SomeProtocol协议。
泛型类型的类型限制语法与泛型函数相似。
例如以下是一个使用类型限制定义的在一个数组中查找值的一个泛型函数findIndex的样例及其使用。
该样例对类型參数施加了一个类型限制:规定类型參数必须符合Equatable协议(也是Swift标准库中定义的一种协议。要求随意符合该协议的类型必须实现==和!=操作符,用来对那种类型的两个值进行比較。全部Swift的标准类型都提供对该协议的支持)。
func findIndex<T:Equatable>(array:T[],valueToFind:T) ->Int?
{
for (index,value) in enumerate(array) {
if value ==valueToFind {
returnindex
}
}
return nil
}
let doubleIndex =findIndex([3.14159,0.1,0.25],9.3)
1.4 协议的泛化
在定义一种协议时,作为协议定义的一部分。能够为协议用到的类型声明一个或多个相关占位类型,相关占位类型是协议用到的类型的占位名或别名,事实上际类型在协议採用时才规定。
相关类型在协议定义中使用typealiaskeyword规定。
例如以下是协议泛化的样例。
样例定义了一个名为Container的协议,Container协议中声明了一个称为ItemType的相关占位类型。用来在协议中作为协议规定的方法需求append的參数类型和脚本方法需求的返回类型的类型占位。
protocol Container {
typealias ItemType
mutating func append(item:ItemType)
var count:Int {get }
subscript(i:Int) ->ItemType {get }
}
以下是该协议的使用样例:
struct IntStack: Container {
// original IntStack implementation
var items =Int[]()
mutating fund push(item:Int) {
items.append(item)
}
mutating func pop() ->Int {
return items.removeLast()
}
// conformance to the Container protocol
typealias ItemType =Int//该行能够去掉,让Swift自己主动进行类型判断
mutating unc append(item:Int) {
self.push(item)
}
var count:Int {
return items.count
}
subscript(i:Int) ->Int {
return items[i]
}
}
在该样例中声明IntStack採用Container协议,因此IntStack须要实现Container协议规定的需求。IntStack在实现Container协议时。能够指定或者让Swift自己主动判断Container协议中定义的相关类型(别名)的实际类型。
1.5、 Where 从句
能够使用 Where 从句为泛型函数、泛型类型、泛型协议中的类型參数或相关类型进一步定义限制或需求。能够在泛型定义中使用 Where 从句规定一个相关类型符合一个确定的协议。或者规定类型參数与一个关联类型的类型同样。
例如以下定义了一个泛型函数allItemsMatch,用来检查两个容器的实例中的相应次序项的值同样。
该泛型函数使用Where 从句规定待比較的两个容器包括的项类型同样。而且符合Equatable协议。
func allItemsMatch<C1:Container,C2:Container where C1.ItemType ==C2.ItemType,C1.ItemType:Equatable>
(someContainer:C1,anotherContainer:C2) ->Bool {
if someContainer.count !=anotherContainer.count {
return false
}
for i in 0..someContainer.count {
if someContainer[i] !=anotherContainer[i] {
return false
}
}
// all items match, so return true
returntrue
}
版权全部,请转载时清楚注明链接和出处,谢谢!