深入源码分析go类型系统

hittata · · 2655 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

深入源码分析go类型系统

 

Ø runtime/type.h  

 go类型描述的静态信息

//type  go类型最通用定义,go的类型系统通过这个数据结构来进行驱动

//Type是类型信息结构体中公共的部分

 20 struct Type

 21 {

 22     uintptr size;     //类型大小

 23     uint32 hash;    //hash

 24     uint8 _unused;

 25     uint8 align;      //对齐

 26     uint8 fieldAlign;  //field对齐

 27     uint8 kind;       //reflect包中的Kind类型就是这个,它是个类型的枚举值

 28     Alg *alg;

 29     void *gc;         //垃圾回收相关

 30     String *string;

 31     UncommonType *x;  //指向指针,该指针指向的struct 中包含该类型实现的函数指针数组

 32     Type *ptrto;

 33     byte *zero;  // ptr to the zero value for this type

 34 };

// 非接口类型method描述数据结构

 36 struct Method

 37 {

 38     String *name;

 39     String *pkgPath;

 40     Type    *mtyp;

 41     Type *typ;

 42     void (*ifn)(void);

 43     void (*tfn)(void);

 44 };

 45

//具体类型的methods集合

 46 struct UncommonType

 47 {

 48     String *name;

 49     String *pkgPath;

 50     Slice mhdr;

 51     Method m[];

 52 };

//methods interface 编译器构造的静态数据结构

 54 struct IMethod

 55 {

 56     String *name;

 57     String *pkgPath;

 58     Type *type;

 59 };

 60 

 61 struct InterfaceType

 62 {

 63     Type;

 64     Slice mhdr;

 65     IMethod m[];

 66 };

 

// 空接口interface{} 

编译器不会为该种类型构造一个静态数据结构

空接口在赋值后才有意义,单单声明个空接口是没有意义的

 

 

Ø runtime/type.h

//接口赋值时编译器构造的动态数据结构

//其他类型赋值给interfac{},编译器动态构造的数据结构

 189 struct Eface

 190 {

 191     Type*   type;  //指向具体类型

 192     void*   data;  //类型变量的值

 193 };

 

//其他类型赋值给非空接口,编译器构造的数据结构

 184 struct Iface

 185 {

 186     Itab*   tab;  //接口动态赋值时数据结构

 187     void*   data; //类型值

 188 };

 

// 具体类型变量赋值给非空接口类型变量时,编译器构造的数据结构

 472 struct  Itab

 473 {

 474     InterfaceType*  inter;   //指向接口静态类型描述,见上文InterfaceType结构

 475     Type*   type;          //指向结构被赋值的具体变量的类型描述

 476     Itab*   link;

 477     int32   bad;

 478     int32   unused;

 479     void    (*fun[])(void); //拷贝具体类型变量的函数指针到该数组

 480 };

 

 

 

 

l 接口是可被实例化的类型,不仅是语言上的约束规范;当我们创建接变量时,将会为其分配部分内存空间(此时接口没有任何价值,不能使用);当将type实例赋值时给接口变量时才分配全部空间(包括实例变量值或指针的拷贝)和初始化全部数据结构。单单声明一个接口变量,而不对其赋值,是没有意义的。

$GOROOT/src/pkg/runtime/runtime.h

 

 178 struct Iface

 179 {

 180     Itab*   tab;

 181     void*   data;

 182 };

 

 

 

 449 struct  Itab

 450 {

 451     InterfaceType*  inter;

 452     Type*   type;

 453     Itab*   link;

 454     int32   bad;

 455     int32   unused;

 456     void    (*fun[])(void);

 457 };

 

上个例子中:

  var m Tester    仅仅创建Iface 数据结构,但是 Itab 和 void * data 都没有赋值(nil),此时变量没有任何意义,使用会引发运行时panic 

(对m进行反射TypeOf 返回nil

(对m进行反射ValueOf 返回空的value,调用其方法会引发panic

只有给赋值一个type 实例变量,才会初始化Itab 和 void * data,接口变量才能真的使用

 

接口变量是用来赋值的,单单声明一个接口变量而不赋值违背了接口设计原则;

接口是用来结构的,接口变量一定要实例化(被赋值);

接口变量可以赋值给另一个接口变量;

 

 

 

反射包是对go类型的更深一个层次抽象,其与go底层数据结构的映射关系如下:

描述类型的数据结构

描述类型变量存储结构的数据结构

runtime/type.h

runtime/runtime.h

reflect/type.go

reflect/value.go

 

 

Type结构

类型信息是静态的,声明一种新类型,编译器只需生成一个该类型的数据结构描述即可;

类型变量是动态的,new或者直接声明一个变量,都要为该变量分配存储空间,同时将该变量与类型信息关联;以便在调用类型方法的时候能够找到正确的入口地址和参数;

 

编译器在编译时即已经确定类型信息和类型方法,在运行时将参数值和调用类型方法绑定,完成方法调用;

go大部分类型检查是在编译器进行的(包括接口赋值),有两个例外是在运行期进行的:

1> 调用反射的方法

2> 接口的查询 t.(TYPE) 

 

 

接口操作

语法

时间点

类型变量赋值给接口 

var i InterfaceA =  &structA{}

编译期间

接口查询

var i InterfaceA =  &structA{}

v, ok :=  i.(TypeB)

运行期间

接口变量赋值给接口变量

var rw IReadWriter = ...

var r IReader = rw

编译期间

 

 

数据结构

runtime/type.h

reflect/type.go

type

20 struct Type

 21 {   

 22     uintptr size;

 23     uint32 hash;

 24     uint8 _unused;

 25     uint8 align;

 26     uint8 fieldAlign;

 27     uint8 kind;

 28     Alg *alg;

 29     void *gc;

 30     String *string;

 31     UncommonType *x;

 32     Type *ptrto;

 33     byte *zero;  // ptr to the zero value for this type

 34 };

244 type rtype struct {  

                                                                 

245 size   uintptr   // size in bytes                                     

246 hash  uint32  // hash of type; avoids computation in hash tables

247  _             uint8     // unused/padding                                    

248  align         uint8     // alignment of variable with this type              

249  fieldAlign    uint8    // alignment of struct field with this type          

250  kind          uint8     // enumeration for C                                 

251  alg    *uintptr  // algorithm table (../runtime/runtime.h:/Alg)       

252  gc      unsafe.Pointer // garbage collection data                           

253  string *string  // string form; unnecessary but undeniably useful    

254  *uncommonType  // (relatively) uncommon fields                      

255  ptrToThis  *rtype 

// type for pointer to this type, if used in binary or has methods

256  zero   unsafe.Pointer // pointer to zero value                             

257 }

UncommonType

非接口类型静态数据结构

36 struct Method

 37 {

 38     String *name;

 39     String *pkgPath;

 40     Type    *mtyp;

 41     Type *typ;

 42     void (*ifn)(void);

 43     void (*tfn)(void);

 44 };

 45 

 46 struct UncommonType

 47 {

 48     String *name;

 49     String *pkgPath;

 50     Slice mhdr;

 51     Method m[];

 52 };

260 type method struct {

 

261 name    *string   // name of method

262 pkgPath *string  // nil for exported Names; otherwise import path

263 mtyp   *rtype    // method type (without receiver)

264 typ  *rtype    // .(*FuncType) underneath (with receiver)

265 ifn  unsafe.Pointer // fn used in interface call (one-word receiver)

266 tfn  unsafe.Pointer // fn used for normal method call

267 } 

273 type uncommonType struct {

274  name    *string  // name of type

275  pkgPath *string  // import path; nil for built-in types like int, string

 276     methods []method // methods associated with type

 277 }

InterfaceType

非空接口类型数据结构

54 struct IMethod

 55 {

 56     String *name;

 57     String *pkgPath;

 58     Type *type;

 59 };

 60 

 61 struct InterfaceType

 62 {

 63     Type;

 64     Slice mhdr;

 65     IMethod m[];

 66 };

311 // imethod represents a method on an interface type

 312 type imethod struct {

 313  name    *string // name of method

 314  pkgPath *string // nil for exported Names; otherwise import path

 315  typ     *rtype  // .(*FuncType) underneath

 316 }

 317 

 318 // interfaceType represents an interface type.

 319 type interfaceType struct {

 320     rtype   `reflect:"interface"`

 321     methods []imethod // sorted by hash

 322 }

内置数据类型

68 struct MapType

 69 {

 70     Type;

 71     Type *key;

 72     Type *elem;

 73     Type *bucket; 

74     Type *hmap;   

 75 };

 

 77 struct ChanType

 78 {

 79     Type;

 80     Type *elem;

 81     uintptr dir;

 82 };

 

 84 struct SliceType

 85 {

 86     Type;

 87     Type *elem;

 88 };

 

90 struct FuncType

 91 {

 92     Type;

 93     bool dotdotdot;

 94     Slice in;

 95     Slice out;

 96 }

 97 

 98 struct PtrType

 99 {

100     Type;

101     Type *elem;

102 };

 

 

325 type mapType struct {

 326     rtype  `reflect:"map"`

 327     key    *rtype // map key type

 328     elem   *rtype // map element (value) type

 329     bucket *rtype // internal bucket structure

 330     hmap   *rtype // internal map header

 331 }                                                                                 

                                                                                       

 296 // chanType represents a channel type.                                                

 297 type chanType struct {                                                                

 298     rtype `reflect:"chan"`                                                            

 299     elem  *rtype  // channel element type                                             

 300     dir   uintptr // channel direction (ChanDir)                                      

 301 }   

                                                                                  

 

339 // sliceType represents a slice type.

 340 type sliceType struct {

 341     rtype `reflect:"slice"`

 342     elem  *rtype // slice element type

 343 }

                                                                                       

 303 // funcType represents a function type.                                               

 304 type funcType struct {                                                                

 305     rtype     `reflect:"func"`

 306     dotdotdot bool     // last input parameter is ...

 307     in        []*rtype // input parameter types

 308     out       []*rtype // output parameter types

 309 }

 

 

 333 // ptrType represents a pointer type.

 334 type ptrType struct {

 335     rtype `reflect:"ptr"`

 336     elem  *rtype // pointer element (pointed at) type

 337 }

 

289 type arrayType struct {                                                               

 290     rtype `reflect:"array"`                                                           

 291     elem  *rtype // array element type                                                

 292     slice *rtype // slice type                                                        

 293     len   uintptr                                                                     

 294 }    

 

 

 

345 // Struct field

 346 type structField struct {

 347     name    *string // nil for embedded fields

 348     pkgPath *string // nil for exported Names; otherwise import path

 349     typ     *rtype  // type of field

 350     tag     *string // nil if no tag

 351     offset  uintptr // byte offset of field within struct

 352 }

 353 

 354 // structType represents a struct type.

 355 type structType struct {

 356     rtype  `reflect:"struct"`

 357     fields []structField // sorted by offset

 358 }

go支持类型系统

 

struct 类型比较特殊,他是一种符合类型

 

函数也是一等公民,也是一种基础类型

 

210 const (

 211     Invalid Kind = iota

 212     Bool

 213     Int

 214     Int8

 215     Int16

 216     Int32

 217     Int64

 218     Uint

 219     Uint8

 220     Uint16

 221     Uint32

 222     Uint64

 223     Uintptr

 224     Float32

 225     Float64

 226     Complex64

 227     Complex128

 228     Array

 229     Chan

 230     Func

 231     Interface

232     Map

 233     Ptr

 234     Slice

 235     String

 236     Struct

 237     UnsafePointer

 238 )

 

 

Value具体映射关系

value 主要是描述类型变量的内存布局

接口是个粘合剂,go在编译时也准备一些数据结构来辅助变量间的运算

 

数据结构

runtime/runtime.h

reflect/value.go

空接口

//空接口

189 struct Eface                                                                          

 190 {                                                                                     

 191     Type*   type;                                                                     

 192     void*   data;                                                                     

 193 };

 

//空接口

278 // emptyInterface is the header for an interface{} value.

 279 type emptyInterface struct {

 280     typ  *rtype

 281     word iword

 282 }   

 283         

非空接口

//非空接口数据描述

184 struct Iface                                                                          

 185 {                                                                                     

 186     Itab*   tab;                                                                      

 187     void*   data;                                                                     

 188 };                                                                                    

470 // layout of Itab known to compilers                                                  

 471 // allocated in non-garbage-collected memory                                          

 472 struct  Itab                                                                          

 473 {   

 474     InterfaceType*  inter;                                                            

 475     Type*   type;                                                                     

 476     Itab*   link;                                                                     

 477     int32   bad;                                                                      

 478     int32   unused;                                                                   

 479     void    (*fun[])(void);                                                           

 480 };  

////非空接口数据描述

 284 // nonEmptyInterface is the header for a interface value with methods.

 285 type nonEmptyInterface struct {

 286     // see ../runtime/iface.c:/Itab

 287     itab *struct {

 288         ityp   *rtype // static interface type

 289         typ    *rtype // dynamic concrete type

 290         link   unsafe.Pointer

 291         bad    int32

 292         unused int32

 293       fun  [100000]unsafe.Pointer

 // method table

 294     }

 295     word iword

 296 }

内置数据类型存储模型

205 struct  Slice

206 {                

207     byte*   array; 

208     uintgo  len;                               

209     uintgo  cap;                               

210 };

 

174 struct String

 175 {

 176     byte*   str;

 177     intgo   len;

 178 };

 

194 struct Complex64

 195 {

 196     float32 real;

 197     float32 imag;

 198 };

 199 struct Complex128

 200 {

 201     float64 real;

 202     float64 imag;

 203 };

 

1931 type SliceHeader struct {                                                             

1932     Data uintptr                                                                      

1933     Len  int                                                                          

1934     Cap  int                                                                          

1935 }

 

1914 type StringHeader struct {                                                            

1915     Data uintptr                                                                      

1916     Len  int                                                                          

1917 }  

Layout of in-memory per-function information prepared by linker

由连接器在内存中位每个函数分配的信息

455 struct  Func

 456 {   

 457  uintptr entry;  // start pc

 458  int32   nameoff;// function name

 459     

 460   int32   args;   // in/out args size

 461   int32   frame;  // legacy frame size; use pcsp if possible

 462     

 463     int32   pcsp;

 464     int32   pcfile;

 465     int32   pcln;

 466     int32   npcdata;

 467     int32   nfuncdata;

 468 };

 

 

 


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:hittata

查看原文:深入源码分析go类型系统

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2655 次点击  
加入收藏 微博
下一篇:Go的内存模型
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传