// 别名 type U int var u U = 10 fmt.Println(reflect.TypeOf(u).Name()) // u 类型名称 fmt.Println(reflect.TypeOf(u).Kind()) // int 基础类型 fmt.Println(reflect.TypeOf(&u).Name()) // 指针类型没有名称 fmt.Println(reflect.TypeOf(&u).Kind()) // 指针类型基础类型是 ptr
a := [2]string{} fmt.Println(reflect.TypeOf(a).Elem().Name()) // string m := map[int]string{} fmt.Println(reflect.TypeOf(m).Elem().Kind()) // string
结构体
1 2 3 4 5 6 7 8 9 10 11 12
type User struct { Name string `json:"name,omitempty" name:"myname"` Age int `json:"age,omitempty"` float float64 `json:"float,omitempty"` p *int `json:"p,omitempty"` s []string `json:"s,omitempty"` m map[int]string `json:"m,omitempty"` desc struct { desc1 string `json:"desc_1,omitempty"` desc2 bool `json:"desc_2,omitempty"` } `json:"desc"` }
var x float64 = 3.1415 fmt.Println(reflect.ValueOf(x)) // 获取变量 fmt.Println(reflect.ValueOf(x).Kind() == reflect.Float64) // true 变量是float64类型 fmt.Println(reflect.ValueOf(x).Int()) // 将变量转成其他类型,reflect: call of reflect.Value.Int on float64 Value
反射可以将“反射类型对象”转换为“接口类型变量”
1 2 3 4 5
type Myint int// Myint类型 var x Myint = 10 v := reflect.ValueOf(x) // 获取值 y := v.Interface() // 转换为接口类型变量 fmt.Printf("%v %T\n", y, y) // 10 main.Myint
判断反射类型变量是否可变更,以及变更
1 2 3 4 5 6
var x float64 = 3.14 v := reflect.ValueOf(&x) // 需要传入指针,才能修改变量的值 fmt.Println(v.CanSet()) // false 无法更改 fmt.Println(v.Elem().CanSet()) // true 可修改 v.Elem().SetFloat(1.11) // 将Elem的值改成对应类型的值 fmt.Println(x) // 1.11
如果要修改反射类型对象的值,取决于其值是否可取地址
判断是否可以取地址
1 2 3 4 5 6 7 8 9
x := 10 a := reflect.ValueOf(10) b := reflect.ValueOf(x) c := reflect.ValueOf(&x) d := reflect.ValueOf(&x).Elem() fmt.Println(a.CanAddr()) // false fmt.Println(b.CanAddr()) // false fmt.Println(c.CanAddr()) // false fmt.Println(d.CanAddr()) // true
修改结构体中的成员变量
1 2 3 4 5 6 7 8 9 10 11 12 13
type T struct { Name string// 元素首字母大写,能够导出 Age int } var t T = T{"mitaka", 18} v := reflect.ValueOf(&t).Elem() // 获取可修改对象 v.Field(0).SetString("abc") // index 0 代表 Name v.Field(1).SetInt(123) // index 1 代表 Age tType := v.Type() s := v.NumField() for i := 0; i < s; i++ { fmt.Println(tType.Field(i).Name, v.Field(i).Kind(), v.Field(i).Interface()) }
// 通过结构体直接修改 funcBenchmarkChangeStruct(b *testing.B) { t := T{S: "abc"} b.ResetTimer() for i := 0; i < b.N; i++ { t.S = "def" } }
// 反射,通过结构体成员序号修改 funcBenchmarkReflectStruct(b *testing.B) { t := T{S: "abc"} v := reflect.ValueOf(&t).Elem() b.ResetTimer() for i := 0; i < b.N; i++ { v.Field(0).SetString("def") } }
// 反射,通过成员名称搜索元素修改 funcBenchmarkReflectStructByName(b *testing.B) { t := T{S: "abc"} v := reflect.ValueOf(&t).Elem() b.ResetTimer() for i := 0; i < b.N; i++ { v.FieldByName("S").SetString("abc") } }
var a *int fmt.Println(reflect.ValueOf(a).IsNil()) // true a 没有初始化内存 nil var b *int = new(int) fmt.Println(reflect.ValueOf(b).IsNil()) // false b有内存地址
var c []int fmt.Println(reflect.ValueOf(c).IsNil()) // true c 没有初始化内存 var d []int = make([]int, 0) fmt.Println(reflect.ValueOf(d).IsNil()) // false
var e int fmt.Println(reflect.ValueOf(e).IsZero()) // true e == 0 var f int = 10 fmt.Println(reflect.ValueOf(f).IsZero()) // false f != 0
var g int8 = 10 fmt.Println(reflect.ValueOf(g).IsValid()) // true 判断值是否越界,-128~127 var h struct{} = struct{}{} fmt.Println(reflect.ValueOf(h).FieldByName("12").IsValid()) // false fmt.Println(reflect.ValueOf(h).MethodByName("123").IsValid()) // false
var i map[interface{}]interface{} fmt.Println(reflect.ValueOf(i).MapIndex(reflect.ValueOf("abc")).IsValid()) // false
funcmain() { u := User{ Name: "mitaka", Age: 18, } b, _ := json.Marshal(u) u1 := map[string]interface{}{} json.Unmarshal(b, &u1) for k, v := range u1 { fmt.Printf("k: %s,v: %+v,%T\n", k, v, v) } }
输出结果
1 2
k: Name,v: mitaka,string k: Age,v: 18,float64
可以看到,结构体中的int类型,反序列化之后,变成float64
通过反射可以解决这个问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
functomap(s interface{}) (map[string]interface{}, error) { out := make(map[string]interface{}) v := reflect.ValueOf(s) if v.Kind() == reflect.Ptr { // 判断传入的类型 v = v.Elem() // 将值转化为结构体中的值 } if v.Kind() != reflect.Struct { return out, errors.New("input must be struct or struct pointer") } t := v.Type() // 将类型转化成结构体 num := v.NumField() for i := 0; i < num; i++ { // 便利类型的值 key := t.Field(i).Name vi := v.Field(i).Interface() out[key] = vi } return out, nil }
输出:
1 2
k: Name,v: mitaka,string k: Age,v: 18,int
或者通过某个tag实现转换
1 2 3 4 5 6
type User struct { Name string`test:"name"` Age int`test:"age"` F float32`test:"f"` I int8`test:"i"` }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
functomap(in interface{}, tag string) (map[string]interface{}, error) { out := make(map[string]interface{}) t := reflect.TypeOf(in) v := reflect.ValueOf(in) if t.Kind() == reflect.Pointer { v = v.Elem() } t = v.Type() if t.Kind() != reflect.Struct { return out, errors.New("input must be struct or struct pointer") } for i := 0; i < t.NumField(); i++ { key := t.Field(i).Tag.Get(tag) value := v.Field(i).Interface() out[key] = value } return out, nil }