结构体转map[string]interface{}
1、JSON序列化方式
func main() { u1 := UserInfo{Name: "q1mi", Age: 18} b, _ := json.Marshal(&u1) var m map[string]interface{} _ = json.Unmarshal(b, &m) for k, v := range m{ fmt.Printf("key:%v value:%v\n", k, v) } }
注意:这种方法有个缺点,那就是Go语言中的json
包在序列化空接口存放的数字类型(整型、浮点型等)都会序列化成float64类型。
2、反射
// ToMap 结构体转为Map[string]interface{} func ToMap(in interface{}, tagName string) (map[string]interface{}, error){ out := make(map[string]interface{}) v := reflect.ValueOf(in) if v.Kind() == reflect.Ptr { v = v.Elem() } if v.Kind() != reflect.Struct { // 非结构体返回错误提示 return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v) } t := v.Type() // 遍历结构体字段 // 指定tagName值为map中key;字段值为map中value for i := 0; i < v.NumField(); i++ { fi := t.Field(i) if tagValue := fi.Tag.Get(tagName); tagValue != "" { out[tagValue] = v.Field(i).Interface() } } return out, nil }
3、第三方库structs
Github上也有现成的轮子,例如第三方库:https://github.com/fatih/structs。它使用的自定义结构体tag是structs
:
// UserInfo 用户信息 type UserInfo struct { Name string `json:"name" structs:"name"` Age int `json:"age" structs:"age"` } m3 := structs.Map(&u1) for k, v := range m3 { fmt.Printf("key:%v value:%v value type:%T\n", k, v, v) }
4、嵌套结构体转map[string]interface{}
1)structs
本身是支持嵌套结构体转map[string]interface{}
的,遇到结构体嵌套它会转换为map[string]interface{}
嵌套map[string]interface{}
的模式。
2)使用反射转成单层map
// ToMap2 将结构体转为单层map func ToMap2(in interface{}, tag string) (map[string]interface{}, error) { // 当前函数只接收struct类型 v := reflect.ValueOf(in) if v.Kind() == reflect.Ptr { // 结构体指针 v = v.Elem() } if v.Kind() != reflect.Struct { return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v) } out := make(map[string]interface{}) queue := make([]interface{}, 0, 1) queue = append(queue, in) for len(queue) > 0 { v := reflect.ValueOf(queue[0]) if v.Kind() == reflect.Ptr { // 结构体指针 v = v.Elem() } queue = queue[1:] t := v.Type() for i := 0; i < v.NumField(); i++ { vi := v.Field(i) if vi.Kind() == reflect.Ptr { // 内嵌指针 vi = vi.Elem() if vi.Kind() == reflect.Struct { // 结构体 queue = append(queue, vi.Interface()) } else { ti := t.Field(i) if tagValue := ti.Tag.Get(tag); tagValue != "" { // 存入map out[tagValue] = vi.Interface() } } break } if vi.Kind() == reflect.Struct { // 内嵌结构体 queue = append(queue, vi.Interface()) break } // 一般字段 ti := t.Field(i) if tagValue := ti.Tag.Get(tag); tagValue != "" { // 存入map out[tagValue] = vi.Interface() } } } return out, nil }
参考:结构体转map[string]interface{}的若干方法 | 李文周的博客 (liwenzhou.com)