Lehirt / no_idea

0 stars 0 forks source link

类型系统 #7

Open Lehirt opened 1 year ago

Lehirt commented 1 year ago

类型元数据 runtime._type :

type _type struct {
    size       uintptr
    ptrdata    uintptr // size of memory prefix holding all pointers
    hash       uint32
    tflag      tflag
    align      uint8
    fieldAlign uint8
    kind       uint8
    // function for comparing objects of this type
    // (ptr to object A, ptr to object B) -> ==?
    equal func(unsafe.Pointer, unsafe.Pointer) bool
    // gcdata stores the GC type data for the garbage collector.
    // If the KindGCProg bit is set in kind, gcdata is a GC program.
    // Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
    gcdata    *byte
    str       nameOff
    ptrToThis typeOff
}
Lehirt commented 1 year ago

内置类型元数据:

type slicetype struct {
    typ   _type
    elem  *_type
}

type ptrtype struct {
    typ   _type
    elem  *_type
}

type maptype struct {
    typ    _type
    key    *_type
    elem   *_type
    bucket *_type // internal type representing a hash bucket
    // function for hashing keys (ptr to key, seed) -> hash
    hasher     func(unsafe.Pointer, uintptr) uintptr
    keysize    uint8  // size of key slot
    elemsize   uint8  // size of elem slot
    bucketsize uint16 // size of bucket
    flags      uint32
}
...

自定义类型元数据,还会存在 uncommontype 结构:

type uncommontype struct {
    pkgpath nameOff
    mcount  uint16 // number of methods
    xcount  uint16 // number of exported methods
    moff    uint32 // offset from this uncommontype to [mcount]method
}

方法元数据:

type method struct {
    name nameOff
    mtyp typeOff
    ifn  textOff
    tfn  textOff
}
Lehirt commented 1 year ago

空接口 interface{}

type eface struct {
    _type *_type
    data  unsafe.Pointer
}

非空接口:

type iface struct {
    tab  *itab
    data unsafe.Pointer
}
type itab struct {
    inter *interfacetype
    _type *_type
    hash  uint32 // copy of _type.hash. Used for type switches.
    _     [4]byte
    fun   [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
type interfacetype struct {
    typ     _type
    pkgpath name
    mhdr    []imethod
}

itab 可以从 _type 中获取到变量类型元数据的方法元数据,并从 fun 中获取到。

Lehirt commented 1 year ago

类型断言

// 1. 空接口.(具体类型) :e.(*os.File)是要判断e存储的_type是否指向*os.File的类型元数据。
var e interface{}
//......
r,ok := e.(*os.File)

// 2. 非空接口.(具体类型) :rw.(*os.File)是要判断rw的动态类型是否为*os.File。
var rw io.ReadWriter
//......
r,ok := rw.(*os.File)

// 3. 空接口.(非空接口):e.(io.ReadWriter)是判断e的动态类型是否实现了io.ReadWriter接口。
var e interface{}
//......
rw,ok := e.(io.ReadWriter)

// 4. 非空接口.(非空接口):w.(io.ReadWriter)是要判断w的动态类型是否实现了io.ReadWriter接口。
var w io.Writer
//......
rw,ok := w.(io.ReadWriter)

如何判断动态类型_type是否实现了xxx接口? 使用 <接口,动态类型> 的 itab 缓存判断,若缓存不存在,则使用动态类型的方法列表匹配接口的方法列表并更新缓存。

Lehirt commented 1 year ago

反射:获取类型的元数据(字段、方法etc.)

reflect 包中存在一套与 runtime 相同的类型struct

反射核心类型:reflect.Typereflect.Value


type Type interface {
    Align() int //对齐边界
    FieldAlign() int //作为结构体字段的对齐边界
    Method(int) Method //获取方法数组中第i个Method
    MethodByName(string) (Method, bool) //按照名称查找方法
    NumMethod() int //方法列表中可导出方法的数目
    Name() string //类型名称
    PkgPath() string //包路径
    Size() uintptr //该类型变量占用字节数
    String() string //获取类型的字符串表示
    Kind() Kind //类型对应的reflect.Kind
    Implements(u Type) bool //该类型是否实现了接口u
    AssignableTo(u Type) bool //是否可以赋值给类型u
    ConvertibleTo(u Type) bool //是否可转换为类型u
    Comparable() bool //是否可比较

    //只能应用于某些Kind的方法
    //Int*, Uint*, Float*, Complex*: 
    Bits() int

    //Array,Ptr,Slice,Map: 
    Elem() Type
    //Array
    Len() int

    //Chan:ChanDir, Elem 
    ChanDir() ChanDir

    //Func: 
    In(i int) Type
    NumIn() int
    Out(i int) Type
    NumOut() int
    IsVariadic() bool

    //Map: 
    Key() Type

    //Struct: 
    Field(i int) StructField
    FieldByIndex(index []int) StructField
    FieldByName(name string) (StructField, bool)
    FieldByNameFunc(match func(string) bool) (StructField, bool)  
    NumField() int

    common() *rtype
    uncommon() *uncommonType
}

使用 reflect.TypeOf 可以获取到传入参数的 reflect.Type结构体。

func TypeOf(i interface{}) Type {
    eface := *(*emptyInterface)(unsafe.Pointer(&i))
    return toType(eface.typ)
}

调用reflect.TypeOf(a)时参数a存在以下转换:a -> interface{} -> reflect.emptyInterface -> reflect.Type 。重点是要理解反射如何拿到反射变量的类型元数据。