反射
基本介绍
- 反射可以在运行时动态获取变量的各种信息,比如变量的类型(type)、类别(kind)
- 如果是结构体变量,可以获取到结构体本身的信息(包括结构体的字段、方法)
- 通过反射,可以修改变量的值,可以调用关联的方法
- 使用反射,需要import(“reflect”)
- 示意图
应用场景
- reflect.TypeOf(变量名) 获取变量的类型,返回reflect.Type类型
- reflect.ValueOf(变量名)获取变量的值,返回reflect.Value 是一个结构体类型,通过reflect.Value,可以获取该变量的很多信息
- 变量、interface{} 和 reflect.Value 是可以相互转换的,这点在实际开发中经常会用到
基本使用
func reflectTest01(b interface{}) {
rTyp := reflect.TypeOf(b)
fmt.Println("TypeOf", rTyp)
fmt.Printf("TypeOf Type %T \n", rTyp)
value := reflect.ValueOf(b)
fmt.Println("ValueOf", value)
fmt.Printf("ValueOf %T\n", value)
fmt.Println(value.Int() + 13)
iv := value.Interface()
num2 := iv.(int)
fmt.Println(num2)
}
func TestReflect(t *testing.T) {
var num int = 100
reflectTest01(num)
}
结构体
func reflectTest01(stu Student) {
stuType := reflect.TypeOf(stu)
fmt.Println("stuType", stuType)
fmt.Println("stuType Kind", stuType.Kind())
stuValue := reflect.ValueOf(stu)
fmt.Println("stuValue", stuValue)
fmt.Println("stuValue Kind", stuValue.Kind())
stuIv := stuValue.Interface()
fmt.Printf("接口 类型 %T \n", stuIv)
student, ok := stuIv.(Student)
if ok {
fmt.Printf("接口 类型 %T \n", student)
}
}
type Student struct {
Name string
Age int
}
func TestReflect(t *testing.T) {
student := Student{
"tom", 13,
}
reflectTest01(student)
}
注意
- reflect.Value.Kind 获取变量的类别,返回的是一个产量
- Type 是类型 Kind是类别,Type和Kind可能相同,可能不同
比如:int Type :int ; Kind:int
Student Type:Student ; Kind:struct - 通过反射可以在让变量在 interface{} 和 Reflect.Value 之间相互转换
- 使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,否则panic
- 通过反射修改变量,注意当使用setXxx方法来设置需要通过对应的指针来完成,同时需要使用reflect.Value.Elem
func TestReflect(t *testing.T) {
i := 10
iValue := reflect.ValueOf(&i)
iValue.Elem().SetInt(20)
fmt.Println(i)
}
练习
func TestReflect(t *testing.T) {
var v float64 = 1.2
value := reflect.ValueOf(v)
vType := value.Type()
vKind := value.Kind()
fmt.Println(vType, vKind, value)
fv, ok := value.Interface().(float64)
if ok {
fmt.Printf("FV 的值 %v 类型 %T \n", fv, fv)
}
}
最佳实践
遍历结构体的方法,调用接头体的方法,获取结构体的标签
func TestReflect(t *testing.T) {
m := Monster{
Name: "黄书狼",
Age: 400,
Score: 30.8,
}
mType := reflect.TypeOf(m)
mValue := reflect.ValueOf(m)
if mValue.Kind() != reflect.Struct {
fmt.Println("expect struct")
return
}
num := mValue.NumField()
fmt.Printf("struct has %d field \n", num)
for i := 0; i < num; i++ {
fmt.Printf("字段 %d 值为%v\n", i, mValue.Field(i))
tagVal := mType.Field(i).Tag.Get("json")
if tagVal != "" {
fmt.Printf("字段 %d : tag为%v\n", i, tagVal)
}
}
methodNum := mValue.NumMethod()
fmt.Printf("struct has %d method \n", methodNum)
mValue.Method(1).Call(nil)
var params []reflect.Value
params = append(params, reflect.ValueOf(10))
params = append(params, reflect.ValueOf(40))
res := mValue.Method(0).Call(params)
fmt.Println("res ", res[0].Int())
}