Arrays
虽然原来的Keeper类型说明了泛型类型不需要存储任何内容或使用它的类型参数,但泛型类型的最常见就是同时具有这两种功能。这就是Array类型。
使用泛型数组是发明泛型类型的原始动机的一部分。由于许多程序需要相同类型的数组,所以泛型数组使代码更安全。
你一直在使用数组,但是只有[Element]的预防,而不是Array
let animalAges: [Int] = [2,5,7,9]
这相当于下面这个数组:
let animalAges: Array = [2,5,7,9]
Array[Int]()
而不是Array
由于Swift数组只允许对元素序列进行索引访问,所以它们对元素类型没有要求。但情况并非总是如此。
Dictionaries
Swift泛型允许多个类型参数和对它们的一系列复杂的限制。它们允许你使用具有关联类型的泛型类型和协议来建立复杂的算法和数据结构。字典就是一个简单的例子。
Dictionary在逗号分隔的泛型参数列表中有两个类型参数,它们位于尖括号之间,您可以在它的声明中看到:
struct Dictionary // etc..
Key和Value表示字典的键和值的类型。但是Key上的注释,Key: Hashable表示的意义很多。冒号之后的所有内容都是类型约束。类型约束指明了该类型参数父类型,以及所需的协议或协议列表。
例如,Dictionary的类型约束要求作为Dictionary键的任何类型都是hashable,因为Dictionary是一个散列映射,必须对其键进行散列,以启用快速查找。
要实例化具有多个类型参数的类型(如Dictionary),只需提供一个逗号分隔的类型参数列表:
let intNames: Dictionary = [42: "forty-two"]
与数组一样,字典在Swift中也有一些特殊的处理,因为它们是内置的,而且非常常见。你已经见过速记表示法[Key: Value],还可以使用类型推断:
let intNames2: [Int: String] = [42: "forty-two", 7: "seven"]
let intNames3 = [42: "forty-two", 7: "seven"]
Optionals
最后,对泛型的讨论如果不提及Optionals,就不完整。Optionals通过枚举实现,但它们也是另一种泛型类型,你可以自己定义它。
假设你正在编写一个应用程序,该应用程序允许用户以表单的形式输入她的生日,但不是必须的。你可能会发现定义enum类型很方便,如下所示:
enum OptionalDate {
case none
case some(Date)
}
类似地,如果另一个表单不要求用户输入她的姓,你可以定义以下类型:
enum OptionalString {
case none
case some(String)
}
然后,你可以捕获用户所输入或未输入的所有信息:
struct FormResults {
// other properties here
var birthday: OptionalDate
var lastName: OptionalString
}
如果你发现新类型在重复做这些,那么你会想把它归纳成一个泛型类型来表示“可能存在的特定类型的值”的概念。因此,你可以这样写:
enum Optional {
case none
case some(Wrapped)
}
此时,你将复制Swift自己的Optional < Wrapped >类型,因为这与Swift标准库中的定义非常接近!事实证明,Optional < Wrapped >接近于一个普通的旧泛型类型,就像你自己编写的类型一样。
只有当你与Optional进行交互时,它才会是一个泛型类型,比如:
var birthdate: Optional = .none
if birthdate == .none {
// no birthdate
}
但是,当然,下面这样的更常见也更传统:
var birthdate: Date? = nil
if birthdate == nil {
// no birthdate
}
实际上,这两个代码块的含义完全相同。
与数组和字典一样,optionals在语言中具有这种语法的特权地位,使使用它们更简洁。但是所有这些特性都提供了访问底层类型的更方便的方法,这只是一个普通的枚举类型。
泛型函数参数
到目前为止,你已经了解了泛型类型在函数、类、结构和枚举中的定义。除了Dictionary之外,所有这些都有一个通用参数。
泛型类型参数列表位于类型名或函数名之后。然后可以在定义的其余部分中使用泛型参数。
这个函数接受两个参数并交换它们的顺序:
func swapped(_ x: T, _ y: U) -> (U, T) {
return (y, x)
}
swapped(33, "Jay") // returns ("Jay", 33)
泛型函数定义展示了语法的一个令人困惑的方面:它同时具有类型参数和函数参数。您拥有类型参数