go 反射
go 反射
1.1 反射介绍
反射就是在运行期间(不是编译期间)探知对象的类型信息和内存结构、更新变量、调用它们的方法
1.1.1 反射的使用场景
- 函数的参数类型是interface{},需要在运行时对原始类型进行判断,针对不同的类型采取不同的处理方式。比如json.Marshal(v interface{})。
- 在运行时根据某些条件动态决定调用哪个函数,比如根据配置文件执行相应的算子函数
1.2 反射弊端
- 代码难以阅读,难以维护。
- 编译期间不能发现类型错误,覆盖测试难度很大,有些bug需要到线上运行很长时间才能发现,可能造成严重用后果。
- 反射性能很差,通常比正常代码慢一到两个数量级。在对性能要求很高,或大量反复调用的代码块里建议不要使用反射。
1.3 反射基础类型
1.3.1 reflect.Type
reflect.Type用于获取类型相关的信息
type Type interface {
Method(int) Method //第i个方法
MethodByName(string) (Method, bool) //根据名称获取方法
NumMethod() int //方法的个数
Name() string //获取结构体名称
PkgPath() string //包路径
Size() uintptr //占用内存的大小
String() string //获取字符串表述
Kind() Kind //数据类型
Implements(u Type) bool //判断是否实现了某接口
AssignableTo(u Type) bool //能否赋给另外一种类型
ConvertibleTo(u Type) bool //能否转换为另外一种类型
Elem() Type //解析指针
Field(i int) StructField //第i个成员
FieldByIndex(index []int) StructField //根据index路径获取嵌套成员
FieldByName(name string) (StructField, bool) //根据名称获取成员
FieldByNameFunc(match func(string) bool) (StructField, bool) //
Len() int //容器的长度
NumIn() int //输出参数的个数
NumOut() int //返回参数的个数
}
1.3.2 reflect.Value
reflect.Value获取、修改原始数据类型里的值.
type Value struct {
// 代表的数据类型
typ *rtype
// 指向原始数据的指针
ptr unsafe.Pointer
}
1.4 反射类型
1.4.1 reflect.Type
1.4.1.1 Kind && String 案例
func fansheinit1() {
typeI := reflect.TypeOf(1)
typeS := reflect.TypeOf("hello")
fmt.Println(typeI)
fmt.Println(typeS)
fmt.Println(typeI.String())
fmt.Println(typeS.String())
fmt.Println(typeI.Kind() == reflect.Int)
fmt.Println(typeS.Kind() == reflect.String)
}