【幼麟实验室】笔记-类型系统

262 阅读3分钟

方法调用

type T struct {
   name string
}

func (t T) F1() {
   fmt.Println(t.name)
}

func main() {
   t := T{name: "eggo"}
   t.F1()
}

方法调用本质上是函数调用。

自定义一个结构体类型T,并给它关联一个方法F1。当调用方法F1时,实际上就是T.F1(t)。方法的接受者作为函数的第一个入参传入。

如何动态获取数据类型信息

Go内置类型

给内置类型定义方法是不允许的

  • bool
  • int、int8、int16、int32、int64、uint、uint8(byte)、uint16、uint32、uint64
  • float32、float64
  • complex64、complex128
  • string
  • rune
  • error
  • slice、map、func

自定义类型

接口类型是无效的方法接受者,因此不能给接口类型关联方法。(例如下面的Test方法)

type MyInt int

type T struct {
   name string
}

type I interface {
   Name() string
}

func (i I) Test() {
    
}

但是不管内置类型还是自定义类型,都有对应的类型描述信息。而且每种类型元数据都是全局唯一的,这些类型元数据共同构成了Go语言的类型系统。

类型元数据信息

runtime._type保存了类型的元数据信息,并且作为每个类型元数据的Header。

type _type struct {
    size       uintptr // 大小
    ptrdata    uintptr // 含有所有指针类型前缀大小
    hash       uint32 // 哈希值,用于快速比较两个类型是否相同
    tflag      tflag // 类型的特征标记
    align      uint8 // 作为整体变量存放时的对齐字节数
    fieldalign uint8 // 当前结构字段的对齐字节数
    kind       uint8 // 基础类型枚举值和反射中的 Kind 一致,kind 决定了如何解析该类型
    alg        *typeAlg // 指向一个函数指针表,该表有两个函数,一个是计算类型 Hash 函数。另一个是比较两个类型是否相同的 equal 函数
    gcdata     *byte // GC 相关
    str        nameOff  // 类型名称字符串在二进制文件段中的偏移量
    ptrToThis  typeOff // 类型元信息指针在二进制文件段中的偏移量
}

在_type之后保存的是各种类型额外需要的描述信息。

例如slice的类型元数据,在_type后有一个_type,指向其存储的元素的类型元数据。[]slice的类型元数据中的_type就指向string类型的元数据(stringtype)

type slicetype struct {
   typ  _type
   elem *_type
}

自定义类型

image.png 自定义类型除了有_type和*_type之外,还有一个uncommontype结构体。

type uncommontype struct {
   pkgpath nameOff // 包路径
   mcount  uint16 // 方法数量,记录了该类型关联了多少个方法
   xcount  uint16 // 可导出的方法数量
   moff    uint32 // 方法元数据组成的数组相对于uncommontype结构体偏移了多少字节
   _       uint32 // unused
}

举例

自定义myslice类型,并为它关联两个方法。

type myslice []string

func (ms myslice) Len() {
   fmt.Println(len(ms))
}

func (ms myslice) Cap() {
   fmt.Println(cap(ms))
}

myslice的类型元数据如下:

image.png 首先是slice的类型元数据,后面是uncommontype记录的信息。假设uncommontype的地址为addrA,加上moff字节的偏移量,就是myslice关联的方法元数据数组。

类型定义和类型别名

类型定义

类型定义会基于已有类型创建新类型,MyType会自立门户拥有自己的元数据,即使MyType的类型元数据和int32的类型元数据没有任何改变。

image.png

类型别名

MyType2和int32会关联到同一个类型元数据。rune和int32就是这样的关系。

image.png