文章目录
反射
反射是指程序运行期对程序本身进行访问和修改的能力。
程序在编译时,变量被转换位内存地址,变量名不会被编译器写入到可执行部分。在运行程序时,程序无法获取本身的信息。
支持反射的语言可以在程序编译期将变量的反射信息,如字段信息、类型信息、结构体信息等整合到可执行文件中去,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。
- C/C++语言没有支持反射功能,只能通过typeid提供非常弱化的程序运行时类型信息。
- Go程序的反射系统无法获取到一个可执行文件空间中或者是一个包中的所有类型信息,需要配合使用标准库中的语法、语法解析器和抽象语法树对源码进行扫描后获得这些信息。
反射的类型对象
获取任意值的类型对象
在Go程序中,使用reflect.TypeOf()函数可以获得任意值的类型对象(reflect.Type),程序通过类型对象可以访问任意值的类型信息。
package main
import (
"fmt"
"reflect"
)
func main() {
var a int
typeOfA := reflect.TypeOf(a)
fmt.Println(typeOfA.Name(), typeOfA.Kind())
}
reflect.TypeOf()取得a的类型对象typeOfA,类型为reflect.Type()
通过typeOfA类型对象的成员函数,可以分别获取到typeOfA变量的类型名为int,种类(Kind)为int.
理解类型和种类
类型就是原生数据类型,如int,string,bool,float32等类型,以及type关键字定义的类型。
种类指的就是对象归属的品种,比如Map,Slice,Chan就是独立的种类。还有type A struct就是属于Struct种类,*A就是属于Ptr。
获取类型名称的反射获取方法是reflect.Type中的Name()方法
获取归属的种类使用的就是reflect.Type()中的Kind()方法
示例:对常量和结构体进行类型信息的获取
package main
import (
"fmt"
"reflect"
)
//定义一个Enum类型
type Enum int
const (
Zero Enum = 0
)
func main() {
//声明一个空结构体
type cat struct {
}
//获取结构体实例的反射类型对象
typeOfCat := reflect.TypeOf(cat{
})
//显示反射类型对象的名称和种类
fmt.Println(typeOfCat.Name(), typeOfCat.Kind())
//获取Zero常量的反射类型对象
typeOfA := reflect.TypeOf(Zero)
//显示反射类型对象的名称和种类
fmt.Println(typeOfA.Name(), typeOfA.Kind())
}
输出:
cat struct
Enum int
看了这个例子可以粗略的理解到它们之间的区别:
类型就是type定义的那个类型名称
种类就是type定义的那个类型的原始类型
指针与指针指向的元素
Go程序中对指针获取反射对象时,可以通过reflect.Elem()方法获取这个指针指向的元素类型。相当于做了一个&#