go语言设计与实现-语言基础-阅读笔记
函数调用
- 传值:函数调用时会对参数进行拷贝,被调用方和调用方两者持有不相关的两份数据;
- 传引用:函数调用时会传递参数的指针,被调用方和调用方两者持有相同的数据,任意一方做出的修改都会影响另一方。
Go 语言选择了传值的方式,无论是传递基本类型、结构体还是指针,都会对传递的参数进行拷贝
- 通过堆栈传递参数,入栈的顺序是从右到左;
- 函数返回值通过堆栈传递并由调用者预先分配内存空间;
- 调用函数时都是传值,接收方会对入参进行复制再计算;
接口
接口也是 Go 语言中的一种类型,它能够出现在变量的定义、函数的入参和返回值中并对它们进行约束,不过 Go 语言中有两种略微不同的接口,一种是带有一组方法的接口,另一种是不带任何方法的 interface{}
Go 语言使用 iface 结构体表示第一种接口,使用 eface 结构体表示第二种空接口,两种接口虽然都使用 interface 声明,但是由于后者在 Go 语言中非常常见,所以在实现时使用了特殊的类型。
type eface struct { // 16 bytes _type *_type data unsafe.Pointer }
由于 interface{} 类型不包含任何方法,所以它的结构也相对来说比较简单,只包含指向底层数据和类型的两个指针。从上述结构我们也能推断出 — Go 语言中的任意类型都可以转换成 interface{} 类型。
另一个用于表示接口的结构体就是 iface,这个结构体中有指向原始数据的指针 data,不过更重要的是 itab 类型中的 tab 字段。
type iface struct { // 16 bytes tab *itab data unsafe.Pointer }
_type 是 Go 语言类型的运行时表示。下面是运行时包中的结构体,结构体包含了很多元信息,例如:类型的大小、哈希、对齐以及种类等。
type _type struct { size uintptr ptrdata uintptr hash uint32 tflag tflag align uint8 fieldAlign uint8 kind uint8 equal func(unsafe.Pointer, unsafe.Pointer) bool gcdata *byte str nameOff ptrToThis typeOff }
- size字段存储了类型占用的内存空间,为内存空间的分配提供信息;
- hash字段能够帮助我们快速确定类型是否相等;
- equal字段用于判断当前类型的多个对象是否相等,该字段是为了减少 Go 语言二进制包大小从- typeAlg结构体中迁移过来
itab 结构体是接口类型的核心组成部分,每一个 itab 都占 32 字节的空间,我们可以将其看成接口类型和具体类型的组合,它们分别用 inter 和 _type 两个字段表示
type itab struct { // 32 bytes inter *interfacetype _type *_type hash uint32 _ [4]byte fun [1]uintptr }
除了 inter 和 _type 两个用于表示类型的字段之外,上述结构体中的另外两个字段也有自己的作用:
- hash是对- _type.hash的拷贝,当我们想将- interface类型转换成具体类型时,可以使用该字段快速判断目标类型和具体类型- _type是否一致;
- fun是一个动态大小的数组,它是一个用于动态派发的虚函数表,存储了一组函数指针。虽然该变量被声明成大小固定的数组,但是在使用时会通过原始指针获取其中的数据,所以- fun数组中保存的元素数量是不确定的
反射
三大法则
从 interface{} 变量可以反射出反射对象
从反射对象可以获取 interface{} 变量
要修改反射对象,其值必须可设置
由于 reflect.TypeOf、reflect.ValueOf 两个方法的入参都是 interface{} 类型,所以在方法执行的过程中发生了类型转换
v.Interface().(type)
从接口值到反射对象:
从基本类型到接口类型的类型转换;
从接口类型到反射对象的转换;
从反射对象到接口值:
反射对象转换成接口类型;
通过显式类型转换变成原始类型;
修改变量方式
调用 reflect.ValueOf 函数获取变量指针;
调用 reflect.Value.Elem 方法获取指针指向的变量;
调用 reflect.Value.SetInt 方法更新变量的值
emptyInterface
type
word
reflect.TypeOf 函数的实现原理其实并不复杂,它只是将一个 interface{} 变量转换成了内部的 emptyInterface 表示,然后从中获取相应的类型信息。
reflect.ValueOf 实现也非常简单,在该函数中我们先调用了 reflect.escapes 函数保证当前值逃逸到堆上,然后通过 reflect.unpackEface 方法从接口中获取 Value 结构体
reflect.unpackEface 函数会将传入的接口转换成 emptyInterface 结构体,然后将具体类型和指针包装成 Value 结构体并返回
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号