Swift编程中的泛型解析
泛型代码可以让你写出根据自我需求定义、适用于任何类型的,灵活且可重用的函数和类型。它可以让你避免重复的代码,用一种清晰和抽象的方式来表达代码的意图。
泛型是 Swift 强大特征中的其中一个,许多 Swift 标准库是通过泛型代码构建出来的。事实上,泛型的使用贯穿了整本语言手册,只是你没有发现而已。例如,Swift 的数组和字典类型都是泛型集。你可以创建一个Int数组,也可创建一个String数组,或者甚至于可以是任何其他 Swift 的类型数据数组。同样的,你也可以创建存储任何指定类型的字典(dictionary),而且这些类型可以是没有限制的。
泛型所解决的问题
这里是一个标准的,非泛型函数swapTwoInts,用来交换两个Int值:
func swapTwoInts(inout a: Int, inout b: Int)
let temporaryA = a
a = b
b = temporaryA
}
这个函数使用写入读出(in-out)参数来交换a和b的值,请参考写入读出参数。
swapTwoInts函数可以交换b的原始值到a,也可以交换a的原始值到b,你可以调用这个函数交换两个Int变量值:
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// 输出 "someInt is now 107, and anotherInt is now 3"
swapTwoInts函数是非常有用的,但是它只能交换Int值,如果你想要交换两个String或者Double,就不得不写更多的函数,如 swapTwoStrings和swapTwoDoublesfunctions,如同如下所示:
func swapTwoStrings(inout a: String, inout b: String) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(inout a: Double, inout b: Double) {
let temporaryA = a
a = b
b = temporaryA
}
你可能注意到 swapTwoInts、 swapTwoStrings和swapTwoDoubles函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是Int、String和Double。
但实际应用中通常需要一个用处更强大并且尽可能的考虑到更多的灵活性单个函数,可以用来交换两个任何类型值,很幸运的是,泛型代码帮你解决了这种问题。(一个这种泛型函数后面已经定义好了。)
注意: 在所有三个函数中,a和b的类型是一样的。如果a和b不是相同的类型,那它们俩就不能互换值。Swift 是类型安全的语言,所以它不允许一个String类型的变量和一个Double类型的变量互相交换值。如果一定要做,Swift 将报编译错误。
泛型函数:类型参数
泛型函数可以访问任何数据类型,如:'Int' 或 'String'.
func exchange<T>(inout a: T, inout b: T) {
let temp = a
a = b
b = temp
}
var numb1 = 100
var numb2 = 200
println("Before Swapping Int values are: \(numb1) and \(numb2)")
exchange(&numb1, &numb2)
println("After Swapping Int values are: \(numb1) and \(numb2)")
var str1 = "Generics"
var str2 = "Functions"
println("Before Swapping String values are: \(str1) and \(str2)")
exchange(&str1, &str2)
println("After Swapping String values are: \(str1) and \(str2)")
当我们使用 playground 运行上面的程序,得到以下结果
Before Swapping Int values are: 100 and 200 After Swapping Int values are: 200 and 100 Before Swapping String values are: Generics and Functions After Swapping String values are: Functions and Generics
函数 exchange()用于交换其在上述方案中描述和<T>被用作类型参数值。这是第一次,函数 exchange()被调用返回Int值,第二次调用函数 exchange()将返回String值。多参数类型可包括用逗号分隔在尖括号内。
类型参数被命名为用户定义来了解拥有类型参数的目的。 Swift 提供<T>作为泛型类型参数的名字。 但是型像数组和字典参数也可以命名为键,值,以确定它们输入属于“字典”。
泛型类型
struct TOS<T> {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
var tos = TOS<String>()
tos.push("Swift")
println(tos.items)
tos.push("Generics")
println(tos.items)
tos.push("Type Parameters")
println(tos.items)
tos.push("Naming Type Parameters")
println(tos.items)
let deletetos = tos.pop()
当我们使用 playground 运行上面的程序,得到以下结果
[Swift] [Swift, Generics] [Swift, Generics, Type Parameters] [Swift, Generics, Type Parameters, Naming Type Parameters]
扩展泛型类型
扩展堆栈属性要知道该项目的顶部包含在“extension” 关键字。
struct TOS<T> {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
var tos = TOS<String>()
tos.push("Swift")
println(tos.items)
tos.push("Generics")
println(tos.items)
tos.push("Type Parameters")
println(tos.items)
tos.push("Naming Type Parameters")
println(tos.items)
extension TOS {
var first: T? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
if let first = tos.first {
println("The top item on the stack is \(first).")
}
当我们使用 playground 运行上面的程序,得到以下结果
[Swift] [Swift, Generics] [Swift, Generics, Type Parameters] [Swift, Generics, Type Parameters, Naming Type Parameters]
在堆栈顶部的项目命名类型参数。
类型约束
Swift 语言允许“类型约束”指定类型参数是否从一个特定的类继承,或者确保协议一致性标准。
func exchange<T>(inout a: T, inout b: T) {
let temp = a
a = b
b = temp
}
var numb1 = 100
var numb2 = 200
println("Before Swapping Int values are: \(numb1) and \(numb2)")
exchange(&numb1, &numb2)
println("After Swapping Int values are: \(numb1) and \(numb2)")
var str1 = "Generics"
var str2 = "Functions"
println("Before Swapping String values are: \(str1) and \(str2)")
exchange(&str1, &str2)
println("After Swapping String values are: \(str1) and \(str2)")
当我们使用 playground 运行上面的程序,得到以下结果
Before Swapping Int values are: 100 and 200 After Swapping Int values are: 200 and 100 Before Swapping String values are: Generics and Functions After Swapping String values are: Functions and Generics
关联类型
Swift 允许相关类型,并可由关键字“typealias”协议定义内部声明。
protocol Container {
typealias ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
struct TOS<T>: Container {
// original Stack<T> implementation
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
// conformance to the Container protocol
mutating func append(item: T) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
var tos = TOS<String>()
tos.push("Swift")
println(tos.items)
tos.push("Generics")
println(tos.items)
tos.push("Type Parameters")
println(tos.items)
tos.push("Naming Type Parameters")
println(tos.items)
当我们使用 playground 运行上面的程序,得到以下结果
[Swift] [Swift, Generics] [Swift, Generics, Type Parameters] [Swift, Generics, Type Parameters, Naming Type Parameters]
Where 子句
类型约束使用户能够定义与泛型函数或类型相关联的类型的参数要求。用于定义相关类型的 'where' 子句声明为类型参数列表的一部分要求。 “where”关键字类型参数后面类型和相关类型之间的相关类型的限制,平等关系的列表后放置。
protocol Container {
typealias ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
struct Stack<T>: Container {
// original Stack<T> implementation
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
// conformance to the Container protocol
mutating func append(item: T) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, anotherContainer: C2) -> Bool {
// check that both containers contain the same number of items
if someContainer.count != anotherContainer.count {
return false
}
// check each pair of items to see if they are equivalent
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// all items match, so return true
return true
}
var tos = Stack<String>()
tos.push("Swift")
println(tos.items)
tos.push("Generics")
println(tos.items)
tos.push("Where Clause")
println(tos.items)
var eos = ["Swift", "Generics", "Where Clause"]
println(eos)
当我们使用 playground 运行上面的程序,得到以下结果
[Swift] [Swift, Generics] [Swift, Generics, Where Clause] [Swift, Generics, Where Clause]
您可能感兴趣的文章
- 01-10深入Main函数中的参数argc,argv的使用详解
- 01-10如何寻找数组中的第二大数
- 01-10C++大数模板(推荐)
- 01-10浅谈C/C++中的static与extern关键字的使用详解
- 01-10深入C/C++浮点数在内存中的存储方式详解
- 01-10深入理解C/C++混合编程
- 01-10深入探讨C语言中局部变量与全局变量在内存中的存放位置
- 01-10深入sizeof的使用详解
- 01-10深入解析C中的数值与真假
- 01-10探讨:程序在内存中的分配(常量,局部变量,全局变量,程序代码)问
阅读排行
本栏相关
- 04-02c语言函数调用后清空内存 c语言调用
- 04-02func函数+在C语言 func函数在c语言中
- 04-02c语言的正则匹配函数 c语言正则表达
- 04-02c语言用函数写分段 用c语言表示分段
- 04-02c语言中对数函数的表达式 c语言中对
- 04-02c语言编写函数冒泡排序 c语言冒泡排
- 04-02c语言没有round函数 round c语言
- 04-02c语言分段函数怎么求 用c语言求分段
- 04-02C语言中怎么打出三角函数 c语言中怎
- 04-02c语言调用函数求fibo C语言调用函数求
随机阅读
- 01-10SublimeText编译C开发环境设置
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文
- 04-02jquery与jsp,用jquery
- 08-05织梦dedecms什么时候用栏目交叉功能?
- 01-11ajax实现页面的局部加载
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法实例总结