结构体转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)

浙公网安备 33010602011771号