Golang 的 struct,map,json 互转
小玉不将就
2021年06月06日 21:23
收录于文集
共1篇

Golang 的 struct,map,json 互转

本文用于记录我在 学习阶段遇到的类型转换问题,针对的是 、 之间相互转换的问题,用到的技术 、 三个类库

公共代码区域

  1. package main

  2. import (

  3.    "encoding/json&#​34;

  4.    "fmt&#​34;

  5.    "testing&#​34;

  6. )

  7. type UserInfoVo struct {

  8.    Id   string `json:"id&#​34;`

  9.    UserName string `json:"user_name&#​34;`

  10.    Address []AddressVo `json:"address&#​34;`

  11. }

  12. type AddressVo struct {

  13.    Address string `json:"address&#​34;`

  14. }

  15. var beforeMap = map[string]interface{}{

  16.    "id&#​34;:        "123&#​34;,

  17.    "user_name&#​34;: "酒窝猪&#​34;,

  18.    "address&#​34;:   []map[string]interface{}{{"address&#​34;: "address01&#​34;}, {"address&#​34;: "address02&#​34;}},

  19. }

  20. var User UserInfoVo

  21. func init() {

  22.    User = UserInfoVo{

  23.        Id:       "01&#​34;,

  24.        UserName: "酒窝猪&#​34;,

  25.        Address: []AddressVo{

  26.            {

  27.                Address: "湖南&#​34;,

  28.            },

  29.            {

  30.                Address: "北京&#​34;,

  31.            },

  32.        },

  33.    }

  34. }

一、map, struct 互转

1.map 转 struct

 转 有两种方式 1.是通过第三方包 2.通过 转,再通过 转

第三方包 mapstructure

下载依赖,通过第三方依赖进行转换

go get github.com/goinggo/mapstructure

  1. func TestMapToStructByMod(t *testing.T) {

  2.    var afterStruct =UserInfoVo{}

  3.    before := time.Now()

  4.    err := mapstructure.Decode(beforeMap, &afterStruct)

  5.    if err!=nil{

  6.        fmt.Println(err)

  7.    }

  8.    fmt.Printf("result:%+v \n&#​34;,time.Since(before))

  9.    fmt.Printf("result:%+v \n&#​34;,afterStruct)

  10. }

  1. result:61.757µs

  2. result:{Id:123 UserName: Address:[{Address:address01} {Address:address02}]}

  3. --- PASS: TestMapToStructByMod (0.00s)

  4. PASS

通过 JSON 进行转换

先将 转换成,再通过 JSON 转换成 操作有点繁琐

  1. func TestMapToStructByJson(t *testing.T) {

  2.    beforeMap := map[string]interface {}{

  3.        "id&#​34;:"123&#​34;,

  4.        "user_name&#​34;:"酒窝猪&#​34;,

  5.        "address&#​34;:[]map[string]interface{}{{"address&#​34;: "address01&#​34;}, {"address&#​34;: "address02&#​34;}},

  6.    }

  7.    var afterStruct =UserInfoVo{}

  8.    before := time.Now()

  9.    marshal, err := json.Marshal(beforeMap)

  10.    if err!=nil{

  11.        fmt.Println("marshal:&#​34;,err)

  12.        return

  13.    }

  14.    err = json.Unmarshal(marshal, &afterStruct)

  15.    if err!=nil{

  16.        fmt.Println("unmarshal:&#​34;,err)

  17.        return

  18.    }

  19.    fmt.Println(time.Since(before))

  20.    fmt.Printf("resutlt: %+v&#​34;,afterStruct)

  21. }

  1. 134.299µs

  2. resutlt: {Id:123 UserName:酒窝猪 Address:[{Address:address01} {Address:address02}]}--- PASS: TestMapToStructByJson (0.00s)

  3. PASS

总结

问题:

论性能哪个更佳?

根据结果答案 使用 需要时间是 134.299µs 使用 mapstructure 需要时间是 61.757µs 结果是使用第三方包 性能更好,那么,是因为什么呢?暂且按下不表

2、struct 转 map

JSON 序列化转换

先将 struct 转换成字节数组,再将字节数组转换成 map 打印

  1. func TestStructToMapByJson(t *testing.T) {

  2.    var resultMap interface{}

  3.    before := time.Now()

  4.    jsonMarshal, _ := json.Marshal(User)

  5.    err := json.Unmarshal(jsonMarshal, &resultMap)

  6.    if err != nil {

  7.        fmt.Println(err)

  8.        return

  9.    }

  10.    fmt.Println(time.Since(before))

  11.    fmt.Printf("%+v&#​34;,resultMap)

  12. }

  1. 158.857µs

  2. map[address:[map[address:湖南] map[address:北京]] id:01 user_name:酒窝猪]--- PASS: TestStructToMapByJson (0.00s)

  3. PASS

通过反射转换

通过反射获取 User 的类型与值

  1. func TestStructToMapByReflect(t *testing.T) {

  2.    var resultMap = make(map[string]interface{},10)

  3.    before := time.Now()

  4.    ty:=reflect.TypeOf(User)

  5.    v:=reflect.ValueOf(User)

  6.    for i := 0; i < v.NumField(); i++ {

  7.        resultMap[strings.ToLower(ty.Field(i).Name)]=v.Field(i).Interface()

  8.    }

  9.    fmt.Println(time.Since(before))

  10.    fmt.Printf("%+v&#​34;,resultMap)

  11. }

  1. 13.965µs

  2. map[address:[{Address:湖南} {Address:北京}] id:01 username:酒窝猪]--- PASS: TestStructToMapByReflect (0.00s)

  3. PASS

总结

问题:论性能哪个更佳?

答案是使用反射的效果更快点,没有那么多繁琐的转换,记住在 中进行初始化大小,我试了下,不指定大小与指定大小时间上有 3~4µs 的区别 网络上还有一种方法是使用 包,不过我看了下,该依赖包已经三年没更新了

二、struct, json 互转

1. struct 转 json

  1. func TestStructToJsonByJson(t *testing.T) {

  2.    before := time.Now()

  3.    marshal, _ := json.Marshal(User)

  4.    fmt.Println(time.Since(before))

  5.    fmt.Printf("%s&#​34;, marshal)

  6. }

  1. 116.068µs

  2. {"id&#​34;:"01&#​34;,"user_name&#​34;:"酒窝猪&#​34;,"address&#​34;:[{"address&#​34;:"湖南&#​34;},{"address&#​34;:"北京&#​34;}]}--- PASS: TestStructToJsonByJson (0.00s)

  3. PASS

2.json 转 struct

  1. func TestJsonToStructByJson(t *testing.T) {

  2.    info:=UserInfoVo{}

  3.    marshal, _ := json.Marshal(User)

  4.    before := time.Now()

  5.    json.Unmarshal(marshal,&info)

  6.    fmt.Println(time.Since(before))

  7.    fmt.Printf("%+v&#​34;,info)

  8. }

  1. 23.009µs

  2. {Id:01 UserName:酒窝猪 Address:[{Address:湖南} {Address:北京}]}--- PASS: TestJsonToStructByJson (0.00s)

  3. PASS

三、map, json 互转

1.map 转 json

  1. func TestMapToJson(t *testing.T) {

  2.    before := time.Now()

  3.    marshal, _ := json.Marshal(beforeMap)

  4.    fmt.Println(time.Since(before))

  5.    fmt.Printf("%s&#​34;, marshal)

  6. }

  1. 75.133µs

  2. {"address&#​34;:[{"address&#​34;:"address01&#​34;},{"address&#​34;:"address02&#​34;}],"id&#​34;:"123&#​34;,"user_name&#​34;:"酒窝猪&#​34;}--- PASS: TestMapToJson (0.00s)

  3. PASS

2.json 转 map

  1. func TestJsonToMap(t *testing.T) {

  2.    marshal, _ := json.Marshal(beforeMap)

  3.    resultMap:=make(map[string]interface{},10)

  4.    before := time.Now()

  5.    json.Unmarshal(marshal,&resultMap)

  6.    fmt.Println(time.Since(before))

  7.    fmt.Printf("%+v&#​34;, resultMap)

  8. }

  1. 28.728µs

  2. map[address:[map[address:address01] map[address:address02]] id:123 user_name:酒窝猪]--- PASS: TestJsonToMap (0.00s)

  3. PASS

总结

三者之间的转换更多的是关于如果使用 内库,只有在 转 使用了 转 使用了反射,其他转换,更多的是使用 内置库进行转换