结构体转map[string]interface{}

1、JSON序列化方式

1
2
3
4
5
6
7
8
9
10
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、反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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:

1
2
3
4
5
6
7
8
9
10
// 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 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)

 

posted @   ☞@_@  阅读(250)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
点击右上角即可分享
微信分享提示