反射【Golang】
简介
反射是一种机制,可以在运行时获取操作对象的具体类型,而且通过类型可以获取类的构造,包括成员变量以及成员方法,并且可以动态的调用这些方法或者改变这些变量的值。
反射是一种元编程的实现方案。
Golang一般认为是一门静态语言。静态语言是指编译时就可以确定变量的数据类型的语言,大多数静态语言要求在使用变量之前必须声明数据的类型。常见的静态语言有C、C++、Golang等。
PHP、JavaScript、Python、Perl等语言的变量在使用前不需要声明数据类型,在运行时根据被赋值的值类型才确定数据的类型,此类语言称为动态语言。
而通过反射的能力,Golang语言可以动态的改变对象的值,甚至可以动态改变数据类型,所以反射使得Golang语言具备了动态语言的能力。
原理
空接口
Golang 语言是静态类型语言,变量的类型在编译期间就已经确定了。
Golang 对象头部没有类型指针,通过自身无法获得类型信息,反射所需要的全部信息都来源于接口。
在传统的面向对象的语言例如Java中,所有的类都继承自一个基类(Java中称为Object),所以该类可以指向所有的对象。
Golang 弱化了传统编程语言中继承的概念,其多态通过组合方式实现,Golang 语言中不需要显式的绑定继承关系,而是通过该类是否实现了另一个接口中的方法判断该类是否实现了该接口。
所以如果有一个空接口没有任何方法,那么所有的类都可以认为继承了这个空接口。
//runtime/runtime2.go
type eface struct {
_type *_type
data unsafe.Pointer
}
type _type struct {
size uintptr
...
//类型名称在runtime.moduledata保存的类型范围的偏移量,可以一次找到类型名称的字符串
//所有的类型信息保存在elf文件的.rodata中
str nameOff
}
编译器在编译过程中,将全部变量的类型信息(runtime._type或reflect.rtype,两者底层数据结构一样布,可以做类型转换)保存在.rodata节中。
使用
在运行期间,反射可以探知、修改、创建对象的类型信息和内存结构,具体包括Type和Value。
Type
Type 是Go语言中的数据类型的表示,用来获取Go中类型的信息。
Type本身是interface,表示静态类型(static type), Kind表示底层类型(underlying type)。
Value
Value代表对象的值, 用来做数据的读写。