reflect:在运行时
动态的获取一个变量的类型信息和值信息,就叫反射
Type
反射中将类型划分为两种:
- 类型(Type):基础类型和自定义类型
- 种类(Kind):底层的类型
// tk 显示type和kind
func tk(x interface{}) {
t := reflect.TypeOf(x)
fmt.Printf("type: %v kind: %v \n", t.Name(), t.Kind())
}
// 自定义结构体
type User struct {
Name string `json:"name"`
Gender int `json:"gender"`
}
user := User{
Name: "静静",
Gender: 0,
}
tk(user) // type: User kind: struct
type String string
var s String
tk(s) // type: String kind: string
// 基础类型
var a float32
var b int
var c rune
tk(a) // type: float32 kind: float32
tk(b) // type: int kind: int
tk(c) // type: int32 kind: int32
需要注意的是Array、Slice、Map、Chan、Ptr等类型的变量他们的type名称都是空,需要用Elem()获取,如
// map
m := map[string]interface{}{}
tk(m) // type: kind: map
// 切片
arr := make([]interface{}, 0)
tk(arr) // type: kind: slice
// 指针
u := &user
tk(u) // type: kind: ptr
Value
定义一个struct来解释
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
u := &User{}
- 获取类型信息
t = reflect.TypeOf(u)
// 如果是指针,获取指向的变量
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
for i := 0; i < t.NumField(); i++ {
fmt.Printf("%s %s\n", t.Field(i).Name, t.Field(i).Type) // 打印字段名和字段类型
}
// 输出如下:
// ID int
// Name string
- 获取值信息
v = reflect.ValueOf(u)
// 如果是指针,获取指向的变量
if v.Kind() == reflect.Ptr {
t = t.Elem()
}
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Field(i))
}
- 混着获取
v := reflect.ValueOf(u)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
fmt.Println(t.Name())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i).Interface()
switch value := value.(type) {
case int:
fmt.Printf("%6s: %v = %d\n", field.Name, field.Type, value)
case string:
fmt.Printf("%6s: %v = %s\n", field.Name, field.Type, value)
default:
}
}
- 封装一个map转struct的函数
// M2s map转struct
// 根据struct的字段或者标签转
func M2s(m map[string]interface{}, s interface{}) {
v := reflect.ValueOf(s)
if v.Kind() != reflect.Ptr {
panic("s must be a ptr")
}
// 从map获取值
get := func(key, tag string) (value interface{}) {
for k, v := range m {
if k == key || k == tag {
value = v
break
}
}
return value
}
v = v.Elem()
length := v.NumField()
for i := 0; i < length; i++ {
value := get(v.Type().Field(i).Name, v.Type().Field(i).Tag.Get("json"))
if value != nil && v.Field(i).Kind() == reflect.ValueOf(value).Kind() {
v.Field(i).Set(reflect.ValueOf(value))
}
}
}