Go struct to json

最近做了一些将go中结构体输出到json的事情,各种花样输出,在这里整理一下。

问题1:如何将struct转成json?

这是最简单的一种情况,直接使用encoding/json包中的函数就可以了:

package main

import (
    "encoding/json"
    "fmt"
)

type Item struct {
    Label string
    Value int32
    URL   string
}

func main() {
    item := Item{"hello", 127, "http://test.com"}
    bdata, err := json.Marshal(item)
    if err == nil {
        fmt.Println(string(bdata))
    } else {
        fmt.Println(err)
    }
}

结果:

{"Label":"hello","Value":127,"URL":"http://test.com"}

问题2:我想自定义输出json的key怎么弄?

使用struct的tag即可:

type Item struct {
    Label string `json:"name"`
    Value int32  `json:"value"`
    URL   string `json:"url"`
}

结果:

{"name":"hello","value":127,"url":"http://test.com"}

问题3:有的字段不是必须的,如果为空就不输出呢?

比如URL字段可能为空,如果为空的话就不希望输出了。

func main() {
    item := Item{"hello", 127, ""}
    bdata, err := json.Marshal(item)
    if err == nil {
        fmt.Println(string(bdata))
    } else {
        fmt.Println(err)
    }
}

结果:

{"label":"hello","value":127,"url":""}

可以使用omitempty标签来达到这个目的:

type Item struct {
    Label string `json:"label"`
    Value int32  `json:"value"`
    URL   string `json:"url,omitempty"`
}

结果:

{"label":"hello","value":127}

问题4:我想忽略某一个具体的字段

方法一:可以直接使用这个标签:

type User struct {
    Name     string `json:"name"`
    Email    string `json:"email"`
    Password string `json:"-"`
}

方法二:如果struct是别人定义的不允许我们修改这个标签,除了我们自定义一个struct外,还可以使用匿名struct:

func main() {
    user := User{"valineliu", "1749118121@qq.com", "password"}
    bdata, err := json.Marshal(struct {
        *User
        Password bool `json:"password,omitempty"`
    }{
        User: &user,
    })
    if err == nil {
        fmt.Println(string(bdata))
    }
}

结果:

{"name":"valineliu","email":"1749118121@qq.com"}

这里使用了嵌套结构体的概念,外面的Password字段覆盖了里面UserPassword字段,然后通过问题3里的技巧,达到忽略某个字段的目的。

问题5:临时添加一个或多个字段

这个就比较简单了,自定义一个struct即可:

type User struct {
    Name     string `json:"name"`
    Email    string `json:"email"`
    Password string `json:"password"`
}

type PublicUser struct {
    *User
    Password bool   `json:"password,omitempty"`
    Token    string `json:"token"`
}

func main() {
    user := User{"valineliu", "1749118121@qq.com", "password"}
    publicUser := PublicUser{
        User:  &user,
        Token: "test_token",
    }
    bdata, err := json.Marshal(publicUser)
    if err == nil {
        fmt.Println(string(bdata))
    }
}

结果:

{"name":"valineliu","email":"1749118121@qq.com","token":"test_token"}

问题6:将多个struct组合成一个json

可能一个服务的数据来自不同的接口,需要组合到一个json里,那么同样自定义一个struct就可以了:

type User struct {
    Name     string `json:"name"`
    Email    string `json:"email"`
    Password string `json:"password"`
}

type Analytics struct {
    Blogs int32 `json:"blogs"`
    Read  int32 `json:"read"`
}

type PublicUser struct {
    *User
    Password bool `json:"password,omitempty"`
    *Analytics
}

func main() {
    user := User{"valineliu", "1749118121@qq.com", "password"}
    analytics := Analytics{100, 200}
    publicUser := PublicUser{
        User:      &user,
        Analytics: &analytics,
    }
    bdata, err := json.Marshal(publicUser)
    if err == nil {
        fmt.Println(string(bdata))
    }
}

结果:

{"name":"valineliu","email":"1749118121@qq.com","blogs":100,"read":200}

问题7:我能自定义一个struct如何转换成json吗?

比如,我们有这样的结构:

type Article struct {
    Title   string    `json:"title"`
    PubTime time.Time `json:"pubtime"`
}

直接Marshal后会是这样:

{"title":"my_title","pubtime":"2019-12-05T20:52:50.759801+08:00"}

如果我们想pubtime输出的时间是时间戳,可以自定义输出形式:

func (a Article) MarshalJSON() ([]byte, error) {
    type Alias Article
    return json.Marshal(struct {
        PubTime int64 `json:"pubtime"`
        Article
    }{
        PubTime: a.PubTime.Unix(),
        Article:   a,
    })
}

然而这样是不行的,执行后会报一个fatal error: stack overflow的错误。这是因为,在自定义的MarshalJSON函数里直接调用了Article.MarshalJSON函数,这样就无限调用了,直到报错。

为了避免出现这个错误,可以定义一个别名(Alias):

func (a Article) MarshalJSON() ([]byte, error) {
    type Alias Article
    return json.Marshal(struct {
        PubTime int64 `json:"pubtime"`
        Alias
    }{
        PubTime: a.PubTime.Unix(),
        Alias:   (Alias)(a),
    })
}

结果:

{"pubtime":1575638467,"title":"my_title"}

完美。

结束

这篇文章的结束不是这个话题的结束。关于go语言中使用json还有很多话题可以讨论,这里仅仅是将go中的struct转换成json输出,此外,还有将json转换成struct,以及自定义MarshalUnmarshal函数等话题。


 Previous
What is physics What is physics
这篇文章是阅读《费恩曼物理学讲义 第一卷 新千年版》第1-3章的阅读笔记。 1. 从一片沙滩开始我们生活在一个多姿多彩的世界中。 想象一下,去年的某一天,我们正在一个美丽的海边沙滩享受着没有工作烦恼的美妙时光。你躺在柔软细密的沙滩上,不
2019-12-07
Next 
Hello World Hello World
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hex
2019-12-04 Valineliu
  You Will See...