@phper
2021-02-09T03:53:13.000000Z
字数 8911
阅读 3095
Golang
type Man struct {Id intName string}s1 := make([]Man, 0)s1 = append(s1, Man{1, "a"})s1 = append(s1, Man{2, "b"})s1 = append(s1, Man{3, "c"})func(v interface{}) {getValue := reflect.ValueOf(v) // Value of vif getValue.Kind() != reflect.Slice {panic("need slice kind")}l := getValue.Len()for i := 0; i < l; i++ {value := getValue.Index(i) // Value of itemtypel := value.Type() // Type of itemif typel.Kind() != reflect.Struct {panic("need struct kind")}fmt.Printf("type-kind: %s, type-name: %s, value: %v\n", typel.Kind(), typel.Name(), value.Interface())num := value.NumField()for j := 0; j < num; j++ {fmt.Printf("name: %s, type: %s, value: %v\n", typel.Field(j).Name, value.Field(j).Type(), value.Field(j).Interface())}fmt.Println()}}(s1)
执行打印:
type-kind: struct, type-name: Man, value: {1 a}name: Id, type: int, value: 1name: Name, type: string, value: atype-kind: struct, type-name: Man, value: {2 b}name: Id, type: int, value: 2name: Name, type: string, value: btype-kind: struct, type-name: Man, value: {3 c}name: Id, type: int, value: 3name: Name, type: string, value: c
根据示例:
通过 reflect.ValueOf(v) 得到 v 的 Value 对象,它的 Len() 方法可以得到切片的长度;
通过 Value 对象的 Index(i) 方法得到第 i 的元素 Value 对象,然后通过 Value 对象得到 Type 对象;
值得注意的是:
Index 方法可以适用于获取 Array, Slice, or String 其中的字段
Len 方法获取长度,可以适用于 Array, Chan, Map, Slice, or String
Filed 方法用于Struct的其中字段。
NumField 方法,用于获取Struct的长度。
package mainimport ("fmt""reflect")type User struct {Id int `json:"id"`Name string `json:"name"`addr string `json:"_"`}func main(){u := User{Id:1001, Name:"aaa" , addr:"bbb"}t := reflect.TypeOf(u)v := reflect.ValueOf(u)for i := 0; i < v.NumField(); i++ {if v.Field(i).CanInterface() { //判断是否为可导出字段fmt.Printf("%s %s = %v -tag:%s n",t.Field(i).Name,t.Field(i).Type,v.Field(i).Interface(),t.Field(i).Tag)}}}
执行打印:
Id int = 1001 -tag:json:"id"Name string = aaa -tag:json:"name"
注:当结构体中含有非导出字段时,v.Field(i).Interface()会panic, 所以使用v.Field(i).CanInterface()先判断一下
package mainimport ("reflect""fmt")type User struct {Id intName stringAddress Address}type Address struct {Add stringRes int}func main(){u := User{Id:1001, Name:"aaa" , Address:Address{Add:"ccccccccc", Res:12}}t := reflect.TypeOf(u)v := reflect.ValueOf(u)for i := 0; i < v.NumField(); i++ {//判断是否为可导出字段if v.Field(i).CanInterface() {//判断是否是嵌套结构if v.Field(i).Type().Kind() == reflect.Struct{structField := v.Field(i).Type()for j :=0 ; j< structField.NumField(); j++ {fmt.Printf("%s %s = %v -tag:%s \n",structField.Field(j).Name,structField.Field(j).Type,v.Field(i).Field(j).Interface(),structField.Field(j).Tag)}} else {fmt.Printf("%s %s = %v -tag:%s \n",t.Field(i).Name,t.Field(i).Type,v.Field(i).Interface(),t.Field(i).Tag)}}}}
打印:
Id int = 1001 -tag:Name string = aaa -tag:Add string = ccccccccc -tag:Res int = 12 -tag:
package mainimport ("reflect""fmt")func main(){var data []intdata = []int{1, 2, 3, 4}//反射值v := reflect.ValueOf(data)//数组/切片长度dataNum := v.Len()for i := 0; i < dataNum; i++ {fmt.Printf("%v, ", v.Index(i).Interface())}}
打印:
1,2,3,4,
package mainimport ("fmt""reflect")type Student struct {Name string `json:"name"`Age uint `json:"age"`}type Teacher struct {Name string `json:"name"`Gender uint `json:"gender"`}// StructSliceToMapSlice : struct切片转为map切片func StructSliceToMapSlice(source interface{}) {// 判断,interface转为[]interface{}v := reflect.ValueOf(source)if v.Kind() != reflect.Slice {panic("ERROR: Unknown type, slice expected.")}l := v.Len()ret := make([]interface{}, l)for i := 0; i < l; i++ {ret[i] = v.Index(i).Interface()}// 转换之后的结果变量res := make([]map[string]interface{}, 0)// 通过遍历,每次迭代将struct转为mapfor _, elem := range ret {data := make(map[string]interface{})objT := reflect.TypeOf(elem)objV := reflect.ValueOf(elem)for i := 0; i < objT.NumField(); i++ {data[objT.Field(i).Name] = objV.Field(i).Interface()}res = append(res, data)}fmt.Printf("==== Convert Result ====\n%+v\n", res)}func main() {var people []interface{}// 切片添加Student元素stu1 := Student{Name: "Ame",Age: 18,}stu2 := Student{Name: "Maybe",Age: 20,}people = append(people, stu1)people = append(people, stu2)// 切片添加Teacher元素tech := Teacher{Name: "Rotk",Gender: 0,}people = append(people, tech)StructSliceToMapSlice(people)}
打印:
==== Convert Result ====[map[Age:18 Name:Ame] map[Age:20 Name:Maybe] map[Gender:0 Name:Rotk]]
func MapToStruct(mapData map[string]string, result interface{}) error {if reflect.ValueOf(result).Kind() != reflect.Ptr {return e.setErrorInfo(errors.New("第二参数请传指针变量!"))}if reflect.ValueOf(result).IsNil() {return e.setErrorInfo(errors.New("第二参数不能是空指针!"))}//获取元素值v := reflect.ValueOf(result).Elem()t := v.Type()//遍历结构体for i := 0; i < t.NumField(); i++ {//看下是否有sql别名sqlTag := t.Field(i).Tag.Get("sql")var fieldName stringif sqlTag != "" {fieldName = strings.Split(sqlTag, ",")[0]} else {fieldName = t.Field(i).Name}//从map中取值value, ok := mapData[fieldName]if !ok {continue}switch v.Field(i).Kind() {case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:res, err := strconv.ParseInt(value, 10, 64)if err != nil {return e.setErrorInfo(err)}v.Field(i).SetInt(res)case reflect.String:v.Field(i).SetString(value)case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:res, err := strconv.ParseUint(value, 10, 64)if err != nil {return e.setErrorInfo(err)}v.Field(i).SetUint(res)case reflect.Float32:res, err := strconv.ParseFloat(value, 32)if err != nil {return e.setErrorInfo(err)}v.Field(i).SetFloat(res)case reflect.Float64:res, err := strconv.ParseFloat(value, 64)if err != nil {return e.setErrorInfo(err)}v.Field(i).SetFloat(res)case reflect.Bool:res, err := strconv.ParseBool(value)if err != nil {return e.setErrorInfo(err)}v.Field(i).SetBool(res)case reflect.Slice:var strArray []stringvar valArray []reflect.Valuevar valArr reflect.ValueelemKind := v.Field(i).Type().Elem().Kind()elemType := t.Field(i).Type.Elem()value = strings.Trim(strings.Trim(value, "["), "]")strArray = strings.Split(value, ",")switch elemKind {case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:for _, e := range strArray {ee, err := strconv.ParseInt(e, 10, 64)if err != nil {return err}valArray = append(valArray, reflect.ValueOf(ee).Convert(elemType))}case reflect.String:for _, e := range strArray {valArray = append(valArray, reflect.ValueOf(strings.Trim(e, "\"")).Convert(elemType))}}valArr = reflect.Append(v.Field(i), valArray...)v.Field(i).Set(valArr)}}return nil}
测试一下:
m1 := map[string]string{"created": "2021-12-12", "departname": "233", "status": "2", "uid": "131733", "username":"EE2"}type User2 struct {Uid string `sql:"uid,auto_increment"`Username string `sql:"username"`Departname string `sql:"departname"`Created string `sql:"created"`Status int64 `sql:"status"`}user3 := new(User2)err := MapToStruct(m1, user3)fmt.Printf("%+v", user3)//输出: &{Uid:131733 Username:EE2 Departname:233 Created:2021-12-12 Status:2}
func MapSliceToStructSlice(mapSliceData []map[string]string, values interface{}) error {//原始struct的切片值destSlice := reflect.ValueOf(values).Elem()//原始单个struct的类型destType := destSlice.Type().Elem()//遍历切片for j := 0; j < len(mapSliceData); j++ {//新建1个原始struct的类型dest := reflect.New(destType).Elem()//遍历结构体for i := 0; i < destType.NumField(); i++ {//看下是否有sql别名sqlTag := destType.Field(i).Tag.Get("sql")var fieldName stringif sqlTag != "" {fieldName = strings.Split(sqlTag, ",")[0]} else {fieldName = destType.Field(i).Name}//从map中取值value, ok := mapSliceData[j][fieldName]if !ok {continue}//无法赋值if !dest.Field(i).CanSet() {continue}switch dest.Field(i).Kind() {case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:res, err := strconv.ParseInt(value, 10, 64)if err != nil {return e.setErrorInfo(err)}dest.Field(i).SetInt(res)case reflect.String:dest.Field(i).SetString(value)case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:res, err := strconv.ParseUint(value, 10, 64)if err != nil {return e.setErrorInfo(err)}dest.Field(i).SetUint(res)case reflect.Float32:res, err := strconv.ParseFloat(value, 32)if err != nil {return e.setErrorInfo(err)}dest.Field(i).SetFloat(res)case reflect.Float64:res, err := strconv.ParseFloat(value, 64)if err != nil {return e.setErrorInfo(err)}dest.Field(i).SetFloat(res)case reflect.Bool:res, err := strconv.ParseBool(value)if err != nil {return e.setErrorInfo(err)}dest.Field(i).SetBool(res)}}//赋值destSlice.Set(reflect.Append(destSlice, dest))}return nil}
或者,我们简化一下套用上面的MapToStruct:
func MapSliceToStructSlice(mapSliceData []map[string]string, values interface{}) error {//原始struct的切片值destSlice := reflect.ValueOf(values).Elem()//原始单个struct的类型destType := destSlice.Type().Elem()//遍历切片for j := 0; j < len(mapSliceData); j++ {//新建1个原始struct的类型dest := reflect.New(destType).Elem()//循环调用err := e.MapToStruct(mapSliceData[j], dest.Addr().Interface())if err != nil {return err}//赋值destSlice.Set(reflect.Append(destSlice, dest))}return nil}
测试一下:
m1 := []map[string]string{{"created": "2021-12-12", "departname": "233", "status": "2", "uid": "131733", "username": "EE2"}, {"created": "2021-12-12", "departname": "233", "status": "2", "uid": "131733", "username": "EE2"}}type User2 struct {Uid int `sql:"uid,auto_increment"`Username string `sql:"username"`Departname string `sql:"departname"`Created string `sql:"created"`Status int64 `sql:"status"`}var user3 []User2err = MapSliceToStructSlice(m1, &user3)if err != nil {fmt.Println(err.Error())return}fmt.Printf("%#v", user3)
打印结果如下:
[]main.User2{main.User2{Uid:131733, Username:"EE2", Departname:"233", Created:"2021-12-12", Status:2}, main.User2{Uid:131733, Username:"EE2", Departname:"233", Created:"2021-12-12", Status:2}}