golang 的encoding/json包

理解 Go 语言中的 encoding/json

Go 语言通过 encoding/json 包提供了对 JSON 数据的强大支持,包括序列化、反序列化、自定义处理、数组处理、任意结构解析以及流式处理等。

1. 基本使用

1.1 结构体字段与 JSON 的映射

在 Go 中,结构体的字段可以通过 json 标签(JSON Tag)与 JSON 字段进行映射。如果不指定 json 标签,默认使用结构体字段名的蛇形命名(小写)作为 JSON 字段名。

go 复制代码
type P struct { // 未使用json标签,自动根据字段名称进行绑定
    Name    string
    Age     int
    Address string
    Sex     string
    Time    time.Time
}

type Person struct {
    Name    string `json:"name"`
    Age     int    `json:"age"`
    Address string `json:"-"`
    Sex     string `json:"sex,omitempty"`
}
  • 结构体 P :未定义 json 标签,序列化时会使用结构体字段名作为 JSON 字段名。
  • 结构体 Person
    • NameAge 使用 json 标签映射为 nameage
    • Address 使用 - 标签,表示不会被序列化。
    • Sex 使用 omitempty,当字段为空时不会被序列化。

1.2 序列化与反序列化

go 复制代码
func main() {
    p1 := P{
        Name:    "Jon",
        Age:     20,
        Address: "beijing",
        Sex:     "男",
        Time:    time.Now(),
    }

    p2 := Person{
        Name:    "hon",
        Age:     20,
        Address: "beijing",
        Sex:     "",
    }

    // 编码(序列化)
    json1, err := json.Marshal(p1)
    // 处理错误
    fmt.Println(string(json1))
    // 输出示例: {"Name":"Jon","Age":20,"Address":"beijing","Sex":"男","Time":"..."}

    json2, err := json.Marshal(p2)
    // 处理错误
    fmt.Println(string(json2))
    // 输出示例: {"name":"hon","age":20}

    // 解码(反序列化)
    var p3 Person
    err = json.Unmarshal(json1, &p3)
    // 处理错误
    fmt.Printf("%+v\n", p3)
    // 输出: {Name:Jon Age:20 Address: Sex:男}

    err = json.Unmarshal(json2, &p3)
    // 处理错误
    fmt.Printf("%+v\n", p3)
    // 输出: {Name:hon Age:20 Address: Sex:}
}
  • json.Marshal:将 Go 结构体序列化为 JSON 字符串。
  • json.Unmarshal:将 JSON 字符串反序列化为 Go 结构体。

2. 自定义 JSON 序列化与反序列化

有时候,默认的序列化和反序列化方式无法满足需求,这时可以通过实现 MarshalJSONUnmarshalJSON 方法来自定义行为。

2.1 自定义类型示例

go 复制代码
type Massachusetts struct {
    Name string
}

type P3 struct {
    Name    string
    Address *Massachusetts
}

// 自定义 MarshalJSON 方法
func (m *Massachusetts) MarshalJSON() ([]byte, error) {
    return json.Marshal(struct {
        State string `json:"state"`
    }{
        State: m.Name,
    })
}

func Customize() {
    address := Massachusetts{Name: "beijing"}
    p := P3{
        Name:    "jon",
        Address: &address,
    }

    // 编码
    jsonBytes, err := json.Marshal(p)
    // 处理错误
    fmt.Println(string(jsonBytes))
    // 输出: {"Name":"jon","Address":{"state":"beijing"}}
}
  • Massachusetts 结构体通过自定义 MarshalJSON 方法,将 Name 字段序列化为 state 字段。

3. 处理 JSON 数组

Go 中的切片(Slice)和数组(Array)可以很方便地序列化为 JSON 数组,反向亦然。

3.1 JSON 数组示例

go 复制代码
type P4 struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func JsonArray() {
    people := []P4{
        {Name: "p1", Age: 22},
        {Name: "p2", Age: 23},
    }

    jonsBytes, err := json.Marshal(people)
    // 处理错误
    fmt.Println(string(jonsBytes))
    // 输出: [{"name":"p1","age":22},{"name":"p2","age":23}]
}
  • JsonArray 函数展示了如何将切片序列化为 JSON 数组,以及如何进行反序列化。

4. 解析任意结构的 JSON 数据

在处理来自外部系统的 JSON 数据时,通常无法提前知道其具体结构。Go 提供了 map[string]interface{}interface{} 来处理这种情况。

4.1 任意结构 JSON 示例

go 复制代码
func JsonAny() {
    jsonString := `{
        "name":"p1",
        "Age":21,
        "email":"[email protected]"
    }`

    var m map[string]interface{}
    err := json.Unmarshal([]byte(jsonString), &m)
    // 处理错误
    fmt.Printf("%+v\n", m)
    // 输出: map[Age:21 email:[email protected] name:p1]
}
  • JsonAny 函数展示了如何将任意结构的 JSON 字符串解析为 map[string]interface{},方便后续操作。

5. 流式处理 JSON 数据

对于大型 JSON 数据,逐行读写(流式处理)比一次性加载整个文件更加高效。Go 提供了 json.Decoderjson.Encoder 来处理流式 JSON 数据。

5.1 使用 json.Decoder 解码流式 JSON

go 复制代码
func JsonNewDecoder() {
    jsonData := `{"name":"John", "age":23}`
    reader := strings.NewReader(jsonData)
    decoder := json.NewDecoder(reader)

    var p P4
    if err := decoder.Decode(&p); err != nil {
        fmt.Println(err)
    }
    fmt.Printf("%+v\n", p)
    // 输出: {Name:John Age:23}
}
  • JsonNewDecoder 函数展示了如何使用 json.Decoderio.Reader 中逐行读取和解析 JSON 数据。

5.2 使用 json.Encoder 编码流式 JSON

go 复制代码
func JsonNewEncoder() {
    p := P4{Name: "p1", Age: 22}
    writer := &strings.Builder{}
    encoder := json.NewEncoder(writer)

    if err := encoder.Encode(&p); err != nil {
        fmt.Println(err)
    }
    fmt.Println(writer.String())
    // 输出: {"name":"p1","age":22}
}
  • JsonNewEncoder 函数展示了如何使用 json.Encoder 将 Go 数据结构流式写入 io.Writer

6. 时间类型的序列化与反序列化

在处理包含时间字段的 JSON 数据时,默认的序列化格式为 RFC3339。如果需要自定义时间格式,可以通过自定义类型实现。

6.1 自定义时间格式示例

go 复制代码
type CustomTime time.Time

func (ct CustomTime) MarshalJSON() ([]byte, error) {
    return []byte(fmt.Sprintf("\"%s\"", time.Time(ct).Format("2006-01-02 15:04:05"))), nil
}

func (ct *CustomTime) UnmarshalJSON(b []byte) error {
    str := string(b)
    str = str[1 : len(str)-1] // 去除双引号
    t, err := time.Parse("2006-01-02 15:04:05", str)
    if err != nil {
        return err
    }
    *ct = CustomTime(t)
    return nil
}

type P5 struct {
    Name      string     `json:"name"`
    CreatedAt CustomTime `json:"created_at"`
}

func CustomTimeExample() {
    p := P5{
        Name:      "jon",
        CreatedAt: CustomTime(time.Now()),
    }

    jsonBytes, err := json.Marshal(p)
    // 处理错误
    fmt.Println(string(jsonBytes))
    // 输出: {"name":"jon","created_at":"2025-04-03 23:48:31"}

    var p2 P5
    err = json.Unmarshal(jsonBytes, &p2)
    // 处理错误
    fmt.Printf("%+v\n", p2)
    // 输出: {Name:jon CreatedAt:2025-04-03 23:48:31 +0800 CST}
}
  • CustomTime 类型通过实现自定义的 MarshalJSONUnmarshalJSON 方法,定义了时间的序列化和反序列化格式。

总结

Go 语言的 encoding/json 包提供了灵活而强大的工具来处理 JSON 数据。无论是基本的序列化和反序列化,还是复杂的自定义行为、数组处理、任意结构解析以及流式处理,encoding/json 都能很好地满足需求。理解并掌握这些功能,有助于在开发中高效地处理各种 JSON 数据相关的任务。

相关推荐
chxii29 分钟前
19.go日志包log
网络·golang
审计侠32 分钟前
Go语言-初学者日记(四):包管理
开发语言·后端·golang
阮瑭雅2 小时前
Java语言的Web安全
开发语言·后端·golang
东方雴翾2 小时前
Dart语言的3D可视化
开发语言·后端·golang
程序员勋勋13 小时前
【GoLang】etcd初始化客户端时不会返回错误怎么办
后端·golang·etcd
东方苾梦4 小时前
Elixir语言的游戏音效
开发语言·后端·golang
云闲不收5 小时前
垃圾回收——三色标记法(golang使用)
jvm·算法·golang
唐静蕴8 小时前
Kotlin语言的安全开发
开发语言·后端·golang
储悠然9 小时前
Lisp语言的物联网数据分析
开发语言·后端·golang
东方珵蕴9 小时前
COBOL语言的折线图
开发语言·后端·golang