Go反射机制
反射
什么是反射?为什么需要用到反射?
反射是程序能够检测自身结构的机制,程序可以利用反射这个机制动态修改变量的值、调用函数和方法、甚至可以创建新的数据类型和结构。
但是反射带来最大的弊端就是性能问题,其次就是代码脆弱,问题可能在运行过程中才会被发现,以及代码可读性,可维护性。
反射三个经典定律:
- 反射能把interface{}转换成反射对象;
- 反射能把反射对象还原成interface{}类型变量;
- 要修改反射对象,其值必须可设置;
反射需要访问类型相关信息时,需要用到reflect.TypeOf;需要修改反射值,需要用到reflect.ValueOf。
reflect.TypeOf
reflect.TypeOf函数将变量转换成reflect.Type接口,reflect.Type接口定义了一系列方法,通过这些方法可以获取类型的相关信息;
reflect.Type:
- Kind():获取变量在Go中的基础类型;
- Elem():可以判断类型为any的数据结构所存储的元素类型,可接收底层参数必须是指针、切片、数组、通道、映射表;
- Size():获取对应类型所占的字节大小;
- Comparable():判断一个类型是否可以被比较;
- Implements():判断一个类型是否实现某一个接口;
- ConvertibleTo():判断一个类型是否可以转换成另外一个指定类型;
1 | type rFace interface { |
reflect.ValueOf
reflect.ValueOf函数将变量转换成reflect.Value结构体变量,包含类型信息和实际值,并且这个结构体定义了很多方法,通过这些
方法可以直接操作Value字段ptr所指向的实际数据;
reflect.Value:
- Type():获取一个反射值的类型;
- Elem():获取一个接口或者指针指向的值,如果不是这两种类型则会panic;
- Set():如果需要通过反射来修改反射值,则必须这个反射值必须是可寻址的;
- Interface():获取反射值原本的值;
1 | type myStruct struct { |
函数
可以通过反射来获取函数的所有信息,也可以通过反射调用函数;
通过反射操作函数:
- 获取函数信息:TypeOf(),NumIn(),NumOut(),In(),Out(),Name(),String()
- 反射调用函数:ValueOf(),Call()
1 | func CompareMax(a []int, b []int, params ...[]int) int { |
结构体
通过反射访问结构体中的字段、访问字段的Tag、修改字段、调用结构体的方法等,常见用于orm引擎;
通过反射操作结构体:
- 访问字段:NumField(),Field(),FieldByName();
- 修改字段:SetString(),SetInt();
- 访问Tag:structTag.Lookup(),structTag.Get();
- 调用方法:MethodByName(),Call();
1 | type PersonModel struct { |
reflect.DeepEqual
判断两个变量是否完全相等的函数
Todo: 解析如何判断不同类型变量是否相等(源码);
1 | func BaseUseReflectDeepEqual() { |
备注
https://golang.design/go-questions/stdlib/reflect/how/
https://golang.halfiisland.com/essential/senior/105.reflect.html