泛型
-
泛型编程是一种可以保持类型安全性的代码重用技术。
-
可以认为泛型是 **多态 (polymoyphism) ** 的一种形式,而多态则是指一个接口或名称可以通过多个类型进行访问的现象。
至少有四种不同的概念,可以归纳到 多态编程 这个范畴里:
- 可以定义多个同名但是类型不同的方法。这种用法叫做 重载(overloading),或者更技术地说,这是一种 专属多态 (ad hod polymorphism)。
- 当一个函数或方法接受类 C 作为参数的时候,我们也可以给它传递 C 的派生类,这种用法叫做 子类型多态 (subtype polymorphism)。
- 当一个函数 (通过尖括号语法) 接受泛型参数的时候,我们管这个函数叫做 泛型函数 (generic function),类似地,还有泛型类型和泛型方法。这种用法叫做 参数化多态 (parametric polymorphism)。这些泛型化的参数,叫做 泛型 (generics)。
- 我们可以定义一个协议并让多个类型实现它。这是另外一种更加结构化的 专属多态。
泛型类型
-
恒等函数 (identify function)
func identity<A>(_ value: A) -> A { return value } -
Optional 的定义
enum Optional<Wrapped> { case none case some(Wrapped) }可以把 Optional 当作一个 类型构建器 (type constructor):给它传递一个具体类型 (例如:Int),它就会创建一个新的具体类型 (例如:Optional<Int>)。
扩展泛型类型
在 Swift 里,很多集合类型都是泛型类型 (例如: Array, Set 和 Dictionary)。但是,泛型这项技术本身可不仅仅用在表达集合类型上。它的应用几乎贯穿了整个 Swift 标准库的实现,例如:
- Optional 用泛型参数抽象它包装的类型。
- Result 有两个泛型参数:分别表示成功和失败这两种结果对应的值的类型。
- Unsafe[Mutable]Pointer 用泛型参数表示指针指向的对象的类型。
- Key paths 中使用了泛型表示根类型以及路径的值类型。
- 各种表示范围的类型,使用了泛型表达范围的上下边界。
泛型和 Any
通常,泛型和 Any 的用途是类似的,但它们有截然不同的表现。在没有泛型的编程语言里,Any 通常用来实现和泛型同样的效果,但是却缺少了类型安全性。这通常意味着要使用一些运行时特性,例如内省 (introspection) 或动态类型转换,把 Any 这种不确定的类型变成一个确定的具体类型。而泛型不仅能解决绝大部分同样的问题,还能带来编译期类型检查以及提高运行时性能等额外的好处。
基于泛型的设计
泛型在程序设计之初就可以派上用场,它们可以在众多类型中剥离出共享的罗及并生成模板代码。
extension URLSession {
func load<A>(_ r: Resource<A>,
callback: @escaping (Result<A, Error>) -> ()) {
dataTask(with: r.url) { data, response, err in
callback(Result {
if let e = err { throw e }
guard let d = data else { throw NoDataError() }
return try.r.parse(d)
})
}.resume()
}
}
现在,我们就能用表示用户信息的资源调用 load,并且在回调函数里,得到一个 User 对象或者一个错误了:
URLSession.shared.load(profile) { result in
print(result)
}