本小节讲了一些关于泛型底层
的知识点和一些特殊状况下
的使用。能够当作扩充知识面去学习。git
func min<T: Comparable>(_ x: T, _ y: T) -> T {
returny<x?y:x
}
复制代码
编译器没法为这个函数直接生产代码
,缘由以下:github
1.编译器不知道T的```变量大小```
2.编译器不知道须要调用的<函数是否有重载,因此也不知道须要调用的```函数的地址```
复制代码
swift 为函数引入了一套间接的中间层
来解决这个问题,引入了一个容器,编译器会把泛型放到这个容器中 对于泛型的参数,编译器还维护了一个或者多个目睹表(witness table)
,包括一个值目睹表
,以及每一个协议约束的协议目睹表
。 这些表将运行时的函数动态派发
到正确的实现中。 表里实际上放的都是指针
。同时还记录了类型大小和对齐方式
。swift
光看泛型特化这个词很难理解它的用法和意思,后面咱们会讲。app
使用泛型特化的缘由: 你们先了解一个swift的设计目标: "编译一次,动态派发"
swift 泛型API只须要知道泛型函数或者类型的声明,并不关心实现
。 因此结果的代码不是那么直接。这会致使运行时性能低
函数
swift库中有不少泛型的使用,性能开销很容易叠加。性能
这里就引入了泛型特化(generic specialization)
来避免这个没必要要的开销。 泛型特化的本质: 编译器按照具体的参数类型
将函数进行复制
。 文章一开始的例子中,可能针对于Int的参数类型特化出一个方法是这样的学习
func min(_ x: Int, _ y: Int) -> Int {
returny<x?y:x
}
复制代码
泛型特化不只能去掉虚拟派发的开销
, 还可让内联
等进一步优化成为可能优化
泛型特化的决定在编译时
进行。特化的参数类型极可能是你常常使用
的具体类型, 若是你常常使用Int 只用过一次float 那么就会特化出上面的函数。spa
缺点:泛型定义和调用在同一个文件中
时,泛型特化才能工做,只能在模块内使用😅(标准库中的泛型方法除外,由于标准库的定义对于全部模块都是可见的)设计
由于泛型特化是一个很严重的限制,因此编译器引入了一个标志来启用全模块优化
能够经过向 swiftc 传递 -whole-module-optimization 来开启全模块优化
通常都是在发布版本中
进行这项操做,
优势:
大幅度提高性能 缺点:
会带来更长的编译时间
@_specialize 是一个非官方
的标签,计划未来会引入到标准库中。 做用:将你的泛型代码进行指定版本的特化,使其在其余模块中
也可用。(你必需要指明想要进行特化的类型列表) 使用以下:
@_specialize(exported: true, where T == Int)
@_specialize(exported: true, where T == String)
public func min<T: Comparable>(_ x: T, _ y: T) -> T {
returny<x?y:x
}
复制代码
over~