类型元数据
在Go语言中像byte、int8、int16、int32、int64、string、slice、func、map…等等,这些属于内置类型,而我们自己通过 type T struct 定义的类型属于自定义类型。
数据类型虽然多,但是不管是内置类型还是自定义类型,都有对应的类型描述信息,称为它的『类型元数据』,而且每种类型的元数据都是全局唯一的,这些类型元数据共同构成了Go语言的类型系统。
像类型名称、类型大小、对齐边界、是否为自定义类型等,是每个类型元数据都要记录的信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//src/runtime/type.go
type _type struct {
size uintptr
ptrdata uintptr // size of memory prefix holding all pointers
hash uint32
tflag tflag
align uint8
fieldAlign uint8
kind uint8
equal func(unsafe.Pointer, unsafe.Pointer) bool
gcdata *byte
str nameOff
ptrToThis typeOff
}
它被放到了runtime._type结构体中,作为每个类型元数据的Header。在_type之后存储的是各种类型额外需要描述的信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
type arraytype struct {
typ _type
elem *_type //指向存储元素的类型元数据
slice *_type
len uintptr
}
type chantype struct {
typ _type
elem *_type
dir uintptr
}
type slicetype struct {
typ _type
elem *_type
}
type functype struct {
typ _type
inCount uint16
outCount uint16
}
type ptrtype struct {
typ _type
elem *_type
}
type structtype struct {
typ _type
pkgPath name
fields []structfield
}
type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod
}
如果是自定义的类型,后面还会有一个uncommentype结构体:
1
2
3
4
5
6
7
type uncommontype struct {
pkgpath nameOff //记录类型所在包路径
mcount uint16 // 记录该类型关联到多少个方法
xcount uint16 // number of exported methods
moff uint32 // 记录的是这些方法元数据组成的数组相对于这个uncommentype结构体偏移了多少字节
_ uint32 // unused
}
例如基于[]string定义的一个新的自定义类型myslice:
1
2
3
4
5
6
7
8
type myslice []string
func(ms myslice) Len() {
fmt.Println(len(ms))
}
func(ms myslice) Cen() {
fmt.Println(cap(ms))
}
myslice的类型元数据首先是[]string类型的描述信息,然后在后面加上uncommontype结构体:
1
2
3
4
5
//myslice结构体
struct {
slicetype
uncommontype
}
通过uncommontype这里记录的信息,就可以找到myslice定义的方法元数据在哪儿了。如果uncommontype的地址为addrA加上moff字节的偏移就是myslice关联的方法元数据数组。
写法区别
再来看下这两种写法的区别:
1
2
type MyType1 = int32
type Mytype2 int32
MyType1这种写法叫做给类型int32取别名,实际上MyType1和int32会关联到同一个元数据,属于同一种类型,rune 和 int32 就是这样的关系。
1
MyType1 ——————> int32类型元数据 <—————— int32
而MyType2这种写法属于基于已有类型创建的新类型,MyType2会自立门户,拥有自己的类型元数据。即使MyType2相对于int32来说并没有做任何改变,它们两个对应的类型元数据也已经不同了。
1
2
3
MyType2 ——————> MyType2类型元数据
int32 ——————> int32类型元数据