Go语言反射reflect
Go语言反射的使用方法及底层原理…
反射指的是在程序运行期间对程序本身进行访问和修改的能力.
不支持反射的语言:
程序在编译时,变量转换为内存地址,变量名不会被编译器写入到可执行部分.在运行程序时,程序无法获取自身的信息.
支持反射的语言:
可以在程序编译期间将变量的反射信息,比如字段名称 , 类型信息 ,
结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期间获取类型的反射信息,并且有能力修改它们.
Go程序在运行期间使用reflect包访问程序的反射信息
reflct包实现了运行时反射,允许程序操作任意类型的对象.典型的用法是静态类型interface{}保存一个值,通过TypeOf获取其动态类型信息,该函数返回一个Type类型值,调用ValueOf函数返回一个Value类型值,该值代表运行时的数据.Zero接受一个一个Type类型参数,并返回一个代表该类型零值的Value类型值.
Go程序的反射系统无法获取到一个可执行文件空间中或者是一个包中的所有类型信息,需要配合使用标准库中对应的词法,语法解析器和抽象语法树(
AST)对源码进行扫描后获得这些信息.
通过反射获取类型信息
通过反射获取类型信息:(reflect.TypeOf()和reflect.Type)
使用reflect.TypeOf()函数可以获得任意值的类型对象eflect.Type,程序通过类型对象可以访问任意值的类型信息.
例子:
1 |
|
代码输出:
1 |
|
理解反射的类型( Type )和种类( Kind )
在使用反射的时候,需要首先理解类型(Type)和种类(Kind)的区别。编程中,使用最多的是类型,但在反射中,当需要区分一个大品种的类型时,就会用到种类(Kind)。例如,需要统一判断类型中的指针时,使用种类(Kind)信息就较为方便。
反射种类(kind)的定义
Go 程序中的类型(Type)指的是系统原生数据类型,如 int、string、bool、float32 等类型,以及使用 type
关键字定义的类型,这些类型的名称就是其类型本身的名称。例如使用 type A struct{} 定义结构体时,A 就是 struct{} 的类型。
种类(Kind)指的是对象归属的品种,在 reflect 包中有如下定义:
1 |
|
Map、Slice、Chan 属于引用类型,使用起来类似于指针,但是在种类常量定义中仍然属于独立的种类,不属于 Ptr。
type A struct{} 定义的结构体属于 Struct 种类,*A 属于 Ptr。
从类型对象中获取类型名称和种类的例子:
Go 语言中的类型名称对应的反射获取方法是 reflect.Type 中的 Name() 方法,返回表示类型名称的字符串。
类型归属的种类(Kind)使用的是 reflect.Type 中的 Kind() 方法,返回 reflect.Kind 类型的常量。
例子:
1 |
|
reflect.Elem() - 通过反射获取指针指向的元素类型
通过反射获取指针指向的元素类型:reflect.Elem()
Go 程序中对指针获取反射对象时,可以通过 reflect.Elem() 方法获取这个指针指向的元素类型。这个获取过程被称为取元素,等效于对指针类型变量做了一个*
操作,代码如下:
1 |
|