go语言reflection反射
一、反射
1.1简介
Reflection(反射)在计算机中就是表示程序在运行期间能够探知自身结构的能力类型(类型信息、内存结构、更新变量、以及调用方法)
1.2使用场景
- 函数的参数类型是interface{},需要在运行时对原始类型进行判断,针对不同的类型采取不同的处理方式。比如 类型断言,JSON序列化 json.Marshal(v interface{})。
type UserInfo struct {
Name string
Age int
Sex byte `json:"gender"`
}
user := UserInfo{
Name: "大猫",
Age: 18,
Sex: 1,
}
json.Marshal(user) //返回 {"Name":"大猫","Age":18,"gender":1}
- 在运行时根据某些条件动态决定调用哪个函数,比如根据配置文件执行相应的算子函数。
1.3 反射的弊端
- 代码难以阅读,难以维护。
- 编译期间不能发现类型错误,覆盖测试难度很大,有些bug需要到线上运行很长时间才能发现,可能会造成严重用后果。
- 反射性能很差,通常比正常代码慢一到两个数量级。在对性能要求很高,或大量反复调用的代码块里建议不要使用反射。
二、反射的基础数据类型
2.1 reflect.Type 中一些 获取类型相关的信息 的方法
type Type interface {
Align() int //Align返回该类型的值在内存中分配时的字节数。
FieldAlign() int //字段对齐(FieldAlign)返回在结构体中作为字段使用时的类型的值在结构体中作为一个字段使用时的字节数。
Method(int) Method //第i个方法
MethodByName(string) (Method, bool) //根据名称获取方法
NumMethod() int //方法的个数
Name() string //获取结构体名称
PkgPath() string //包路径(导入路径)
Size() uintptr //占用内存的大小(存储给定类型的字节大小,类似 unsafe.Sizeof())
String() string //获取字符串表述
Kind() Kind //返回该类型的特定类型 数据类型(种类 比type类型范围大)
Implements(u Type) bool //判断是否实现了某接口
AssignableTo(u Type) bool // 判断是否可赋值另外一种类型
ConvertibleTo(u Type) bool //判断能否转换为另外一种类型(即使返回true 也有可能转换时出现错误)
Comparable() bool // 类型的值是否可比较(即使返回true 也会出现比较问题比如interface type的值是可比较的,但如果它们的动态类型不具有可比性,则比较将出现问题。)
Elem() Type //解析指针
Field(i int) StructField //第i个成员
FieldByIndex(index []int) StructField //根据index路径获取嵌套成员(比如第i个成员是一个结构体或者接口这样的嵌套,想要获取其里面的第j个成员,index就要写成[]int{i,j)
FieldByName(name string) (StructField, bool) //根据名称获取成员
FieldByNameFunc(match func(string) bool) (StructField, bool) //
Len() int //容器的长度
NumIn() int //输出参数的个数
NumOut() int //返回参数的个数
}
2.2 reflect.Value 获取、修改原始数据类型里的值
type Value struct {
// 代表的数据类型
typ *rtype
// 指向原始数据的指针
ptr unsafe.Pointer
flag
}
2.3 如何得到Type呢?通过TypeOf()得到Type类型。就可以使用reflect.Type()里面的方法
typeI := reflect.TypeOf(1234)
typeS := reflect.TypeOf("helloworld")
fmt.Println(typeI) //int
fmt.Println(typeS) //string
fmt.Println(typeI.Kind() == reflect.Int) //true
fmt.Println(typeS.Kind() == reflect.String) //true
typeUser := reflect.TypeOf(&User{}) //这里的User就是自定义的空的结构体 : type User struct{}
fmt.Println(typeUser) //*User
fmt.Println(typeUser.Kind()) //ptr
fmt.Println(typeUser.Elem().Kind()) //struct
2.4 reflect.Type()里面方法 一些细致讲解(暂时还没写,以后在补连接)
2.5 如何获得Value?通过ValueOf()得到Value。
iValue := reflect.ValueOf(12345)
sValue := reflect.ValueOf("helloword")
userPtrValue := reflect.ValueOf(User{
Id: 1,
Name: "大猫",
Weight: 75,
Height: 1.72,
})
fmt.Println(iValue) //12345
fmt.Println(sValue) //helloword
fmt.Println(userPtrValue) //&{1 大猫 75 1.72}
2.6 reflect.Value()里面方法 一些细致讲解(暂时还没写,以后在补连接)
2.7 Value转Type
iValue := reflect.ValueOf(12345)
sValue := reflect.ValueOf("helloword")
userPtrValue := reflect.ValueOf(User{
Id: 1,
Name: "大猫",
Weight: 75,
Height: 1.72,
})
iType := iValue.Type()
sType := sValue.Type()
userType := userPtrValue.Type()
//在Type和相应Value上调用Kind()结果一样的
fmt.Println(iType.Kind() == reflect.Int, iValue.Kind() == reflect.Int, iType.Kind() == iValue.Kind())
fmt.Println(sType.Kind() == reflect.String, sValue.Kind() == reflect.String, sType.Kind() == sValue.Kind())
fmt.Println(userType.Kind() == reflect.Ptr, userPtrValue.Kind() == reflect.Ptr, userType.Kind() == userPtrValue.Kind())
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人