go语言中的反射(一)https://developer.aliyun.com/article/1391507
若知道字段名,直接去取该字段:
rv := reflect.ValueOf(p1) rt := reflect.TypeOf(p1) //可以直接取想要的字段 //reflect的type interface,FieldByName方法会返回字段信息以及是否有该字段; if f, ok := rt.FieldByName("Age"); ok { fmt.Printf("field:%+v,value:%+v\n", f.Name, rv.FieldByName("Age")) }
判断一个变量的类型:
rv := reflect.ValueOf(p1) rt := reflect.TypeOf(p1) fmt.Printf("kind is %+v\n", rt.Kind()) fmt.Printf("kind is %+v\n", rv.Kind())
type和value的Kind()方法都可以返回该变量的类型,不过若取得value后发现其是一个零值,那么会返回Kind为Invalidreflect的Kind一共有27种类型,基本揽括了所有golang中的类型
const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer )
*T有方法Add
type T struct{} func (t *T) Add(a, b int) { fmt.Printf("a + b is %+v\n", a+b) }
动态调用
funcName := "Add" typeT := &T{} a := reflect.ValueOf(1) b := reflect.ValueOf(2) in := []reflect.Value{a, b} reflect.ValueOf(typeT).MethodByName(funcName).Call(in)
动态调用含返回值的方法
func (t *T) AddRetErr(a, b int) (int, error) { if a+b < 10 { return a + b, errors.New("total lt 10") } return a + b, nil }
调用
funcName = "AddRetErr" ret := reflect.ValueOf(typeT).MethodByName(funcName).Call(in) fmt.Printf("ret is %+v\n", ret) for i := 0; i < len(ret); i++ { fmt.Printf("ret index:%+v, type:%+v, value:%+v\n", i, ret[i].Kind(), ret[i].Interface()) }
这里的ret[i].Kind(),若非基础类型,会得到interface,如果err不是nil,
if v, ok := ret[1].Interface().(error); ok { fmt.Printf("v is %+v\n", v) }
类型断言会成功,可以用这种方式去判断返回的error是否为空
通过反射修改值
不是所有的反射值都可以修改。对于一个反射值是否可以修改,可以通过CanSet()进行检查。
要修改值,必须满足:
- 可以寻址
- 可寻址的类型:
- 指针指向的具体元素
- slice的元素
- 结构体指针的字段
- 数组指针的元素
1.指针指向的具体元素
需要三步:
取地址:v := reflect.ValueOf(&x)
判断v.Elem()是否可以设值
给v.Elem()设置具体值
ta := 10 vta := reflect.ValueOf(&ta) if vta.Elem().CanSet() { vta.Elem().Set(reflect.ValueOf(11)) } fmt.Println("cant set") fmt.Printf("vta is :%+v\n", vta.Elem())
2.slice中的元素
ts := []int{1, 2, 3} tsV := reflect.ValueOf(ts) if tsV.Index(0).CanSet() { tsV.Index(0).Set(reflect.ValueOf(10)) } fmt.Printf("ts is %+v\n", ts) //输出:ts is [10 2 3]
3.结构体指针的字段
t1 := TagTest{} tV := reflect.ValueOf(t) //结构体指针 t1V := reflect.ValueOf(&t1) fmt.Printf("tV:%+v\n", tV) for i := 0; i < tV.NumField(); i++ { val := tV.Field(i) t1V.Elem().Field(i).Set(val) } fmt.Printf("t1 is %+v\n", t1)
4.数组指针的元素
tsA := [3]int{1, 2, 3} tsAv := reflect.ValueOf(&tsA) if tsAv.Elem().Index(0).CanSet() { tsAv.Elem().Index(0).Set(reflect.ValueOf(10)) } fmt.Printf("tsA is %+v\n", tsA)