golang标准库每日一库之encoding/json

以下为 Go语言 encoding/json的深度解析,涵盖JSON编解码、结构体标签与自定义序列化的核心机制,与标准库(fmt、time等)保持一致的文档风格:


一、核心功能概览

功能分类

核心函数/方法

作用描述

基础编解码

json.Marshal(v), json.Unmarshal(data, v)

结构体与JSON互转

流式处理

json.NewEncoder(w io.Writer), json.NewDecoder(r io.Reader)

高效处理大JSON数据流

结构体标签

` `json:"key,option"` `

控制字段映射规则

自定义序列化

实现 MarshalJSON() ([]byte, error), UnmarshalJSON([]byte) error

完全自定义JSON生成/解析逻辑


二、基础JSON编解码

1. 序列化(Marshal)

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age,omitempty"`
}

user := User{Name: "Alice", Age: 30}
data, err := json.Marshal(user)  // {"name":"Alice","age":30}

// 格式化输出
dataIndent, _ := json.MarshalIndent(user, "", "  ")
/*
{
  "name": "Alice",
  "age": 30
}
*/

2. 反序列化(Unmarshal)

jsonStr := `{"name":"Bob","age":25}`
var user User
err := json.Unmarshal([]byte(jsonStr), &user)  // user = User{Name:"Bob", Age:25}

三、结构体标签高级用法

1. 标签选项详解

标签格式

作用描述

示例

json:"-"

忽略字段

Password string json:"-"``

json:"name"

指定JSON字段名

Name string json:"user_name"``

json:",omitempty"

零值时忽略字段

Age int json:",omitempty"``

json:",inline"

嵌套结构体展开(需自定义Unmarshal)

Profile json:",inline"``

2. 嵌套与匿名结构体

type Address struct {
    City  string `json:"city"`
    Street string `json:"street"`
}

type User struct {
    Name    string `json:"name"`
    Address `json:"address"`  // 嵌套结构体
}

// JSON示例:{"name":"Alice","address":{"city":"Shanghai","street":"Nanjing Rd"}}

四、自定义序列化逻辑

1. 实现 MarshalJSON方法

type CustomTime time.Time

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

// 使用示例
type Event struct {
    Time CustomTime `json:"time"`
}
event := Event{Time: CustomTime(time.Now())}
json.Marshal(event)  // {"time":"2023-08-25"}

2. 实现 UnmarshalJSON方法

func (ct *CustomTime) UnmarshalJSON(data []byte) error {
    str := strings.Trim(string(data), `"`)
    t, err := time.Parse("2006-01-02", str)
    *ct = CustomTime(t)
    return err
}

五、高效处理技巧

1. 流式编码解码

场景

方法

优点

大JSON文件读取

decoder := json.NewDecoder(file)

内存占用恒定

HTTP响应流处理

json.NewEncoder(w).Encode(data)

直接写入网络连接

流式解码示例

file, _ := os.Open("large.json")
decoder := json.NewDecoder(file)

// 读取JSON数组
_, _ = decoder.Token() // 跳过起始的 '['
for decoder.More() {
    var item Item
    _ = decoder.Decode(&item)
    process(item)
}

2. 性能优化策略

  • 预分配内存:为切片/映射设置初始容量
type Response struct {
    Items []Item `json:"items"`
}
res := Response{Items: make([]Item, 0, 100)}  // 预分配100容量
  • 使用 json.RawMessage 延迟解析
type Message struct {
    Header map[string]string   `json:"header"`
    Body   json.RawMessage    `json:"body"`  // 延迟解析
}

六、错误处理与陷阱

1. 常见错误类型

错误场景

解决方案

未导出字段

确保结构体字段首字母大写

循环引用

使用json:"-"忽略或指针引用

数值精度丢失

使用string标签或自定义类型

时间格式不匹配

自定义时间类型或指定time.RFC3339

2. 严格模式校验

decoder := json.NewDecoder(reader)
decoder.DisallowUnknownFields()  // 禁止未知字段

err := decoder.Decode(&config)  // 若JSON含未定义字段,返回错误

七、实战示例

1. 动态JSON解析

var data map[string]interface{}
jsonStr := `{"name":"Alice","age":30,"skills":["Go","Python"]}`
json.Unmarshal([]byte(jsonStr), &data)

// 类型断言获取值
if age, ok := data["age"].(float64); ok {  // JSON数字默认解析为float64
    fmt.Println(int(age))  // 30
}

2. 配置管理系统

type Config struct {
    Port    int      `json:"port"`
    Env     string   `json:"env"`
    Plugins []string `json:"plugins,omitempty"`
}

func LoadConfig(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, err
    }

    var cfg Config
    if err := json.Unmarshal(data, &cfg); err != nil {
        return nil, fmt.Errorf("invalid config: %v", err)
    }
    return &cfg, nil
}

八、扩展工具与库

工具库

优势

使用场景

jsoniter

高性能替代实现(兼容标准库)

高频JSON处理

easyjson

代码生成式高性能序列化

对性能要求极高的场景

mapstructure

将map解析到结构体

动态JSON结构处理


通过系统掌握 encoding/json 库,可高效处理各类JSON数据交互场景。建议结合以下实践:

  • 严格校验:生产环境开启 DisallowUnknownFields
  • 性能监控:使用 go test -bench 测试序列化性能
  • 版本兼容:通过结构体标签处理字段变更(如重命名、弃用字段)
原文链接:,转发请注明来源!