从最开始学编程时,书里就告诉我们,int 是一个内置类型,然后我们也可以通过 class 自定义类型,之后我们发现还可以通过 interface 和 enum 创建更多的类型。这是我们对类型的初步认知,它正确、但不完整。
每个变量都有一个类型,这个变量也只能赋予属于该类型的值。也就是说,我们把一个变量能保存的所有值组成的集合称为类型。
所以类型的本质就是数学里的集合。因此类型理论上也可以作集合运算,比如交集和并集。在有继承的语言里,子类本质上是父类的子集。
在实现编译器时,你不能简单把类型理解为就是一种 class 或 interface,而应该把它看成一种集合。
用户通过 class 定义了一种特定的集合,该集合的元素只能是该 class 的实例。
通过 interface 可以截取 class 中的任何子集。两个 class 即使互不包含,但仍可以存在公共交集,即两个 class 即使互不相干,但依然可以提取出一个公共 interface。
当一个类型 A 可以赋值给另一个类型 B,本质上就是 A 被包含于 B。
特殊类型
A 是一个数组,数组或者是空数组,或者其元素也是数组。
这里 A 就是递归的,我们需要延时解析类型实参,以避免触发递归。
类型别名
类型别名分为透明类型别名和不透明类型别名。
透明类型别名即只创建新名称,但不创建新类型。
比如 type A = int,A 是一个透明类型别名,无论何时,A 和 int 都可以互换,因为它们是相同类型。
不透明类型别名则表示创建了新类型,只不过两者的内部数据刚好一样。
比如 Golang 用 type A int 定义不透明类型别名;用 type A = int 定义透明类型别名。
在类型系统内部,不透明类型别名应该等同于类或接口这些类型,并具备相同处理方式。而透明类型可以完全不存在特定的数据结构来保存。
但为了支持在 IDE 展示时,可以正确展示出别名信息(比如 type A = int; var a: A,当鼠标悬停在 a 是,可以展示 A,而不是 int),可以在类型中插入一个额外的别名字段。但不建议设置新类型数据结构,因为别名类型和原类型的处理方式总是相同。