wift 提供了泛型让你写出灵活且可重用的函数和类型。
Swift 标准库是通过泛型代码构建出来的。
Swift 的数组和字典类型都是泛型集。
你可以创建一个Int数组,也可创建一个String数组,或者甚至于可以是任何其他 Swift 的类型数据数组。
以下实例是一个非泛型函数 exchange 用来交换两个 Int 值:
实例
// 定义一个交换两个变量的函数func swapTwoInts(_ a: inout Int, _ b: inout Int) { let temporaryA = a a = b b = temporaryA} var numb1 = 100var numb2 = 200 print("交换前数据: \(numb1) 和 \(numb2)")swapTwoInts(&numb1, &numb2)print("交换后数据: \(numb1) 和 \(numb2)")
以上程序执行输出结果为:
交换前数据: 100 和 200
交换后数据: 200 和 100
以上实例只试用与交换整数 Int 类型的变量。如果你想要交换两个 String 值或者 Double 值,就得重新写个对应的函数,例如 swapTwoStrings(_:_:) 和 swapTwoDoubles(_:_:),如下所示:
String 和 Double 值交换函数
func swapTwoStrings(_ a: inout String, _ b: inout String) { let temporaryA = a a = b b = temporaryA} func swapTwoDoubles(_ a: inout Double, _ b: inout Double) { let temporaryA = a a = b b = temporaryA}
从以上代码来看,它们功能代码是相同的,只是类型上不一样,这时我们可以使用泛型,从而避免重复编写代码。
泛型使用了占位类型名(在这里用字母 T 来表示)来代替实际类型名(例如 Int、String 或 Double)。
func swapTwoValues<T>(_ a: inout T, _ b: inout T)
swapTwoValues 后面跟着占位类型名(T),并用尖括号括起来(<T>
)。这个尖括号告诉 Swift 那个 T 是 swapTwoValues(_:_:) 函数定义内的一个占位类型名,因此 Swift 不会去查找名为 T 的实际类型。
以下实例是一个泛型函数 exchange 用来交换两个 Int 和 String 值:
实例
// 定义一个交换两个变量的函数func swapTwoValues<T>(_ a: inout T, _ b: inout T) { let temporaryA = a a = b b = temporaryA} var numb1 = 100var numb2 = 200 print("交换前数据: \(numb1) 和 \(numb2)")swapTwoValues(&numb1, &numb2)print("交换后数据: \(numb1) 和 \(numb2)") var str1 = "A"var str2 = "B" print("交换前数据: \(str1) 和 \(str2)")swapTwoValues(&str1, &str2)print("交换后数据: \(str1) 和 \(str2)")
以上程序执行输出结果为:
交换前数据: 100 和 200
交换后数据: 200 和 100
交换前数据: A 和 B
交换后数据: B 和 A
泛型类型
Swift 允许你定义你自己的泛型类型。
自定义类、结构体和枚举作用于任何类型,如同 Array 和 Dictionary 的用法。
接下来我们来编写一个名为 Stack (栈)的泛型集合类型,栈只允许在集合的末端添加新的元素(称之为入栈),且也只能从末端移除元素(称之为出栈)。
图片中从左到右解析如下:
- 三个值在栈中。
- 第四个值被压入到栈的顶部。
- 现在有四个值在栈中,最近入栈的那个值在顶部。
- 栈中最顶部的那个值被移除,或称之为出栈。
- 移除掉一个值后,现在栈又只有三个值了。
以下实例是一个非泛型版本的栈,以 Int 型的栈为例:
Int 型的栈
struct IntStack { var items = [Int]() mutating func push(_ item: Int) { items.append(item) } mutating func pop() -> Int { return items.removeLast() }}
这个结构体在栈中使用一个名为 items 的 Array 属性来存储值。Stack 提供了两个方法:push(_:) 和 pop(),用来向栈中压入值以及从栈中移除值。这些方法被标记为 mutating,因为它们需要修改结构体的 items 数组。
上面的 IntStack 结构体只能用于 Int 类型。不过,可以定义一个泛型 Stack 结构体,从而能够处理任意类型的值。
下面是相同代码的泛型版本:
泛型的栈
struct Stack<Element> { var items = [Element]() mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() }} var stackOfStrings = Stack<String>()print("字符串元素入栈: ")stackOfStrings.push("google")stackOfStrings.push("runoob")print(stackOfStrings.items); let deletetos = stackOfStrings.pop()print("出栈元素: " + deletetos) var stackOfInts = Stack<Int>()print("整数元素入栈: ")stackOfInts.push(1)stackOfInts.push(2)print(stackOfInts.items);
实例执行结果为:
字符串元素入栈:
["google", "runoob"]
出栈元素: runoob
整数元素入栈:
[1, 2]
Stack 基本上和 IntStack 相同,占位类型参数 Element 代替了实际的 Int 类型。
以上实例中 Element 在如下三个地方被用作占位符:
- 创建 items 属性,使用 Element 类型的空数组对其进行初始化。
- 指定 push(_:) 方法的唯一参数 item 的类型必须是 Element 类型。
- 指定 pop() 方法的返回值类型必须是 Element 类型。