reflect包中的具体方法
reflect.TypeOf
、reflect.ValueOf
可以将一个普通的变量转换成『反射』包中提供的Type
和Value
type Person struct { Name string Sex string } func (p *Person) Add(a, b string) { fmt.Printf("me %+v ", a+b) } func (p *Person) AddRes(a, b string) (string, error){ if b == "boy" { return a + b, errors.New("its a boy") } return a+b, nil } func main() { funcName := "Add" typeT := &Person{} a := reflect.ValueOf("li") b := reflect.ValueOf("femal") in := []reflect.Value{a, b} reflect.ValueOf(typeT).MethodByName(funcName).Call(in)//如果是没有参数的函数就需要传nil //me lifemal c := reflect.ValueOf("J") d := reflect.ValueOf("boy") inr := []reflect.Value{c, d} funcName = "AddRes" ret := reflect.ValueOf(typeT).MethodByName("AddRes").Call(inr) fmt.Printf("ret is %+v ", ret) //ret is [Jboy <error Value>] for i := 0; i < len(ret); i++ { fmt.Printf("ret index:%+v, type:%+v, value:%+v ", i, ret[i].Kind(), ret[i].Interface()) } //ret index:0, type:string, value:Jboy //ret index:1, type:interface, value:its a boy }
通过reflect修改值,主要包括(指针指向的具体元素,slice的元素,结构体指针的字段,数组指针的元素)
-
取地址:
v := reflect.ValueOf(&x)
-
CanSet()来判断是否可以设置值
-
判断
v.Elem()
是否可以设值 -
给
v.Elem()
设置具体值
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 ", ts) //10,2,3 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 ", tsA) //小tips,切片返回的就是地址 func main() { ary := [3]int{1, 2, 3}//数组 sli := []int{1, 2, 3}//切片 a := ary b := sli fmt.Printf("ary is %p sli is %p a is %p b is %p ", &ary,sli,&a,b) } // ary is 0xc0000b6020 // sli is 0xc0000b6040 // a is 0xc0000b6060 // b is 0xc0000b6040
通过reflect判断某个实例是否实现了接口
typeT := &Struct{} IF := reflect.TypeOf((*Interface)(nil)).Elem() tv := reflect.TypeOf(typeT) tv.Implements(IF)//true
reflect对struct中的tag解析
获取tag中的值
type TagTest struct { Name string `json:"name_json"` Age int `json:"age_json"` } t := TagTest{Name: "tom", Age: 10} rtt := reflect.TypeOf(t) for i := 0; i < rtt.NumField(); i++ { field := rtt.Field(i) if json, ok := field.Tag.Lookup("json"); ok { fmt.Printf("tag is %+v, value is %+v ", json,field.Tag.Get("json")) } }
field.Tag.Lookup()和field.Tag.Get()方法都是取tag的值,只不过Lookup会用第二个返回值返回是否存在这个tag,而Get方法若不存在这个tag会返回一个空字符串
Name string json:"name,omitempty" omitempty表示如果字段为空,就忽略这个字段
实例解析json数据获取tag
package main import ( "fmt" "reflect" "strings" ) type Person struct { Name string `label:"Person Name: " uppercase:"true"` Age int `label:"Age is: "` Sex string `label:"Sex is: "` Description string } // 按照tag打印结构体 func PrintUseTag(ptr interface{}) error { // 获取入参的类型 t := reflect.TypeOf(ptr) // 入参类型校验 if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { return fmt.Errorf("参数应该为结构体指针") } // 取指针指向的结构体变量 v := reflect.ValueOf(ptr).Elem() // 解析字段 for i := 0; i < v.NumField(); i++ { // 取tag fieldInfo := v.Type().Field(i) tag := fieldInfo.Tag // 解析label tag label := tag.Get("label") if label == "" { label = fieldInfo.Name + ": " } // 解析uppercase tag value := fmt.Sprintf("%v", v.Field(i)) if fieldInfo.Type.Kind() == reflect.String { uppercase := tag.Get("uppercase") if uppercase == "true" { value = strings.ToUpper(value) } else { value = strings.ToLower(value) } } fmt.Println(label + value) } return nil } func main() { person := Person{ Name: "Tom", Age: 29, Sex: "Male", Description: "Cool", } PrintUseTag(&person) }