Table of contents
Interface slices are mapped to structures (dynamic assignment)
Advanced - map is mapped into a structure
First, there is a definition of the following structure
type User struct {
UserName string
UserId int `name:"uid"`
}
Initialize an instance of a struct
u := User{"octoboy", 101}
get field name
First get the Type variable of the variable
t := reflect.TypeOf(u)
It should be noted that if the incoming u is a pointer, such as &User{"octoboy", 101}
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
Here, the type of the variable is obtained through the Kind() function, and if the type is a pointer, it is necessary to use Elem() to obtain the content pointed to by the pointer.
Then traverse the fields of the structure to get its field name
for i := 0; i < t.NumField(); i++ {
fmt.Println(t.Field(i).Name)
}
Output result:
UserName
UserId
Get field type and value
v := reflect.ValueOf(u)
if v.Kind() == reflect.Ptr { //类型为指针 需要取elem
v = v.Elem()
}
To get the value or assignment of a field, you need to use the ValueOf method
for i := 0; i < v.NumField(); i++ {
//v.Field(i).Int() v.Field(i).String() 都可以把值返回出来,相当于断言 类型不匹配会直接panic
//直接断成interface 任意类型
fmt.Println(v.Field(i).Interface())
}
Output result:
sick
101
Continue to output the type of member variables
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Field(i).Kind())
}
Output result:
string
int
set field value
static assignment
//设置字段值
va := reflect.ValueOf(&u) //这里必须使用指针 否则后面调用Set无法使用无地址的值
if va.Kind() == reflect.Ptr { //类型为指针 需要取elem 意为取它指向的内容值
va = va.Elem()
}
for i := 0; i < va.NumField(); i++ {
//两种方法取设置字段的值,第二种更为统一
if va.Field(i).Kind() == reflect.String {
//重要 如果需要使用set取修改u中的值,需要在ValueOf中传入u的地址。否则会因为SetString使用了一个不能被寻址的值而造成panic
va.Field(i).SetString("octoboy")
}
if va.Field(i).Kind() == reflect.Int {
va.Field(i).Set(reflect.ValueOf(123))
}
}
Interface slices are mapped to structures (dynamic assignment)
//练手
values := []interface{}{"octoboy", 123}
for i := 0; i < va.NumField(); i++ {
if reflect.ValueOf(values[i]).Kind() == va.Field(i).Kind() {
va.Field(i).Set(reflect.ValueOf(values[i]))
}
}
Print the variables of the above two structural questions
Output result:
&{octoboy 123}
Advanced - map is mapped into a structure
There is the following code
//练习 把map映射成struct
set := map[string]interface{}{
"UserName": "zyg",
"UserId": 101,
"Age": 19,
"Sex": 1,
}
user := &User{}
MapToStruct(set, user)
fmt.Println(user)
It is required to map the map to the user structure question, that is, if the field name of User exists in the key of the map, then assign the corresponding value to the member variable of the user structure question
have the following implementation
//str类型为interface{} 代表可以传入任意的结构体
func MapToStruct(m map[string]interface{}, str interface{}) {
val := reflect.ValueOf(str)
if val.Kind() != reflect.Ptr {//必须是指针 否则无法用Set赋值
panic(any("must be ptr!"))
}
val = val.Elem()
if val.Kind() != reflect.Struct { //指针指向的必须是结构体
panic(any("must be struct"))
}
for i := 0; i < val.NumField(); i++ {
name := val.Type().Field(i).Name //value转type后取字段名称
if v, ok := m[name]; ok { //如果根据tag做映射,就使用val.Type().Field(i).Tag.Get("name")作为key
if reflect.ValueOf(v).Kind() == val.Field(i).Kind() {
val.Field(i).Set(reflect.ValueOf(v))
}
}
}
}
Summarize
1.TypeOf uses Name to obtain the field name, and can also use Kind to obtain the field type; ValueOf can only use Kind to obtain the field type.
2. Use reflect.ValueOf(u).Type() to convert to type, which can achieve the same effect as reflect.TypeOf(u).
3. If you want to use Set, SetString and other methods to assign values to it, the u in reflect.ValueOf(u) must pass in a pointer, otherwise it cannot be addressed and a panic will occur
4.reflect.ValueOf(u).Interface() can get the value. In actual use, the returned result is often asserted as an interface type to call the interface function