首先是定义
reflect是golang中运行时动态的调用对象的方法和属性的包
然后是使用
reflect最基础的使用就是获取对象的值和类型,方法是reflect.ValueOf和reflect.TypeOf
type aaa struct {
A int
B string
C *time.Time
}
func main() {
aa := aaa{
A: 12,
B: "haha",
}
//结构体struct
ReflectValue := reflect.ValueOf(aa)//{12 haha <nil>}
ReflectType := reflect.TypeOf(aa)//main.aaa kind=struct
//int
bb := 1
ReflectValue = reflect.ValueOf(bb)//1
ReflectType = reflect.TypeOf(bb)//int kind=int
//字符串
cc :="哈哈"
ReflectValue = reflect.ValueOf(cc)//哈哈
ReflectType = reflect.TypeOf(cc)//string kind=string
//map
dd := map[string]string{
"aaa": "bbb",
"ccc": "ddd",
}
ReflectValue = reflect.ValueOf(dd)//map[aaa:bbb ccc:ddd]
ReflectType = reflect.TypeOf(dd)//map[string]string kind=map
//切片和数组
ee :=[]string{"bbb", "ddd"}
ReflectValue = reflect.ValueOf(ee)//[bbb ddd]
ReflectType = reflect.TypeOf(ee)//[]string kind = slice
ff := [2]string{"bbb", "ddd"}
ReflectValue = reflect.ValueOf(ff)//[bbb ddd]
ReflectType = reflect.TypeOf(ff)//[2]string kind = array
//chan 通道
gg := make(chan int, 10)
ReflectValue = reflect.ValueOf(gg)//0xc000116000 一个内存地址
ReflectType = reflect.TypeOf(gg)//chan int kind = chan
//func
hh := func() {
println("我是一个function")
}
ReflectValue = reflect.ValueOf(hh)//0x1186dc0 一个内存地址
ReflectType = reflect.TypeOf(hh)// func() kind = func
//ptr 指针
ii := &aa
ReflectValue = reflect.ValueOf(ii)//&{12 haha <nil>}
ReflectType = reflect.TypeOf(ii)//*main.aaa kind = ptr
fmt.Println(ReflectValue)
fmt.Println(ReflectType)
fmt.Println(ReflectValue.Kind())
}
通过上面各种数据类型的反射使用,相信应该已经能够明白ValueOf和TypeOf的基本用法了吧。其中value.kind反回的是基础类型,type返回的是当前数据类型。
接下来说一下使用的场景
1.通过elem修改参数值,注意:要修改参数值那么ValueOf里面要传入的一定是参数的值针!!!如果传入的不是参数就会panic
例子
aa := aaa{
A: 12,
B: "haha",
}
ReflectValue := reflect.ValueOf(&aa)
// ReflectType := reflect.TypeOf(&aa)
fmt.Println(ReflectValue.Elem())
v := ReflectValue.Elem()
fmt.Println(v.FieldByName("B").CanSet())
if v.FieldByName("B").CanSet() {
v.FieldByName("B").SetString("hehe")
}
fmt.Println(aa)
运行输出
{12 haha <nil>}
true
{12 hehe <nil>}
可以看到变量aa里面B的值已经被修改了
2.动态调用函数 通过Call方法
package main
import (
"fmt"
"reflect"
"errors"
)
//动态调用函数(有参,无参,有返回值)
type T struct {}
func (t *T) Do() {
fmt.Println("Hello, world!")
}
func (t *T) DoWithPara(name string, index int) {
fmt.Println("Hello, ", name, index)
}
func (t *T) DoWithErr() (string, error){
return "hello, world", errors.New("new error")
}
func main() {
name1 := "Do"
name2 := "DoWithPara"
name3 := "DoWithErr"
t := new(T)
reflect.ValueOf(t).MethodByName(name1).Call(nil)
name := reflect.ValueOf("world")
index := reflect.ValueOf(1234)
in := []reflect.Value{name, index}
reflect.ValueOf(t).MethodByName(name2).Call(in)
ret := reflect.ValueOf(t).MethodByName(name3).Call(nil)
fmt.Println(ret[0], ret[1].Interface().(error))
}
3.获取结构体的tag标签
type T struct {
A int `json:"aaa" test:"aaatest"`
B string `json:"bbb" test:"bbbtest"`
}
func main() {
t := T{
A: 123456,
B: "helloworld",
}
tt := reflect.TypeOf(t)
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
if json, ok := field.Tag.Lookup("json"); ok {
fmt.Println(json)
}
test := field.Tag.Get("test")
fmt.Println(test)
}
}
4.通过kind()处理不同分支
a := "haha"
t := reflect.TypeOf(a)
switch t.Kind() {
case reflect.Int:
fmt.Println("int")
case reflect.String:
fmt.Println("string")
default:
fmt.Println("Unknown")
}
参考
https://blog.csdn.net/chen1415886044/article/details/104929244
https://blog.csdn.net/mrbuffoon/article/details/85637417