分享
  1. 首页
  2. 文章

深入源码分析go类型系统

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

深入源码分析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 };


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

本文来自:CSDN博客

感谢作者:hittata

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

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

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

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏