1.初识反射
/*
reflect包:反射;反射代码是不安全的,尽量少用
*/
func main() {
//1.正常的业务代码:获取变量的类型和值
num := 1
fmt.Println("类型:", reflect.TypeOf(num)) // 类型: int
fmt.Println("值:", reflect.ValueOf(num)) // 值: 1
var a int
fmt.Scan(&a)
//2.通过反射获取对象的类型和值
value := reflect.ValueOf(a) //返回一个value对象
//判断类型进行不同的操作 : value.Kind()获取变量类型
if value.Kind() == reflect.Float64 {
fmt.Println(value.Float())
}
if value.Kind() == reflect.Int {
fmt.Println(value.Int())
}
if value.Kind() == reflect.String {
fmt.Println(value.String())
}
}
2.静态变量和动态变量
在反射过程中: 编译的时候就知道变量类型的叫静态类型变量,运行时才知道类型的变量叫动态类型的变量
1.静态类型:声明变量的时候赋予类型的 var name string var age int
2.动态类型:在运行时可能会发生变化 var A any A = 10 A = "abc" //变量A类型发生了变化
3.为什么要用反射
1.我们编写一个函数,但是没约定好入参,不知道传递过来的参数是什么类型,可以使用反射
2.我们定义了一个可以传递任意类型的函数,可以通过反射判断类型进行不同的处理
4.为什么不建议使用反射
1.和反射相关的代码,可读性太低
2.Go语言是静态类型的语言,正常代码开发编译器可以找出编译期的错误;反射代码可能存在运行时才报的错误,一旦panic项目就会停止
3.反射的性能很低,相较于正常的开发,至少慢几个数量级
5.反射获取对象信息
1.获取变量的类型:reflect.TypeOf(变量名) ->Type 1.1:获取变量的种类:Type.Kind() 1.2:获取变量字段的数量:Type.NumField() 获取变量的字段名:Type.Field(i) 1.3获取变量方法的数量:Type.NumMethod() 获取变量的方法名:Type.Method(i) 2.获取变量的值:reflect.ValueOf(变量名) ->Value 2.1:获取字段对应的值:Value.Field(i).Interface()
//定义一个结构体
type User struct {
Name string
Age int
Gender string
}
// 定义结构体的方法:方法名一定要大写,否则反射获取不到
func (user User) Say(msg string) {
fmt.Println(user.Name, "say:", msg)
}
func (user User) PrintInfo() {
fmt.Printf("姓名:%s,年龄:%d,性别,%s", user.Name, user.Age, user.Gender)
}
func main() {
user := User{"张三", 23, "男"}
reflectGetInfo(user)
}
// 通过反射获取传递的对象信息
func reflectGetInfo(v any) {
//1.获取对象的类型
getType := reflect.TypeOf(v)
fmt.Println("类型:", getType.Name()) //类型: User
fmt.Println("上级种类:", getType.Kind()) //上级种类: struct
//2.获取对象字段信息
getValue := reflect.ValueOf(v)
for i := 0; i < getType.NumField(); i++ {
//获取字段的类型
field := getType.Field(i)
//获取字段的值
value := getValue.Field(i).Interface()
fmt.Printf("字段名:%s,字段类型:%s,字段值:%v\n", field.Name, field.Type, value)
}
//3.获取对象的方法
for i := 0; i < getType.NumMethod(); i++ {
method := getType.Method(i)
fmt.Printf("方法名:%s,方法类型:%s\n", method.Name, method.Type)
}
}
6.反射修改变量的值
type Stu struct {
Name string
Age int
Gender string
}
func main() {
a := Stu{"张三", 23, "男"}
//获取指针
value := reflect.ValueOf(&a)
if value.Kind() == reflect.Ptr {
//获取指针对象
newValue := value.Elem()
//判断该类型是否可以修改
if newValue.CanSet() {
if newValue.Kind() == reflect.Int {
newValue.SetInt(168)
}
if newValue.Kind() == reflect.String {
newValue.SetString("测试字符串")
}
if newValue.Kind() == reflect.Float64 {
newValue.SetFloat(3.14)
}
if newValue.Kind() == reflect.Struct {
newValue.FieldByName("Name").SetString("李四")
newValue.FieldByName("Age").SetInt(24)
}
}
}
fmt.Println(a)
}
7.反射调用函数
// 无参无返回值
func fun1() {
fmt.Println("无参无返回值函数")
}
// 有参有返回值
func fun2(a string, b int) {
fmt.Printf("有参无返回值,a:%s,b:%d\n", a, b)
}
// 有参无返回值
func fun3(a, b int) string {
fmt.Printf("有参有返回值,a:%d,b:%d\n", a, b)
return "aaa"
}
func main() {
//无参无返回值函数调用
value1 := reflect.ValueOf(fun1)
fmt.Println(value1.Kind(), value1.Type())
value1.Call(nil)
fmt.Println("======")
// 有参有返回值函数调用
value2 := reflect.ValueOf(fun2)
fmt.Println(value2.Kind(), value2.Type())
args1 := make([]reflect.Value, 2)
args1[0] = reflect.ValueOf("str")
args1[1] = reflect.ValueOf(12)
value2.Call(args1)
fmt.Println("======")
// 有参无返回值函数调用
value3 := reflect.ValueOf(fun3)
fmt.Println(value3.Kind(), value3.Type())
args2 := make([]reflect.Value, 2)
args2[0] = reflect.ValueOf(34)
args2[1] = reflect.ValueOf(12)
res := value3.Call(args2)
fmt.Println("返回值:", res)
}