深入源码分析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),此时变量m 没有任何意义,使用m 会引发运行时panic (对m进行反射TypeOf 返回nil) (对m进行反射ValueOf 返回空的value,调用其方法会引发panic) 只有给m 赋值一个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 }; |
|
有疑问加站长微信联系(非本文作者)