Skip to content

json std

在 Go 中,JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。Go 提供了 encoding/json 标准库,用于处理 JSON 数据,包括序列化(将 Go 数据结构转换为 JSON)和反序列化(将 JSON 转换为 Go 数据结构)。以下是关于 Go JSON 的详细介绍和使用方法:


1. 基础操作:序列化与反序列化

序列化(Struct → JSON)

将 Go 的结构体、切片、Map 等转换为 JSON 格式。

go
package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	Name  string `json:"name"` // 指定 JSON 字段名
	Age   int    `json:"age"`
	Email string `json:"email,omitempty"` // 如果字段为空,则省略
}

func main() {
	user := User{Name: "Alice", Age: 25}
	jsonData, _ := json.Marshal(user) // 转换为 JSON 字节
	fmt.Println(string(jsonData))    // 输出 JSON 字符串
}

输出:

json
{"name":"Alice","age":25}

反序列化(JSON → Struct)

将 JSON 数据解析为 Go 数据结构。

go
func main() {
	jsonData := `{"name":"Alice","age":25}`
	var user User
	json.Unmarshal([]byte(jsonData), &user) // 解析 JSON
	fmt.Println(user.Name)                 // 输出: Alice
}

2. 自定义 JSON 字段

Go 的结构体字段可以通过 json 标签自定义 JSON 字段名或行为:

常用标签说明

  • json:"字段名":指定字段在 JSON 中的名称。
  • json:"-":忽略字段,不参与序列化或反序列化。
  • json:"字段名,omitempty":如果字段是零值(如空字符串、0、nil),序列化时忽略该字段。

示例:

go
type Product struct {
	ID       int     `json:"id"`
	Name     string  `json:"name"`
	Price    float64 `json:"price"`
	Discount bool    `json:"-"`               // 忽略字段
	Stock    int     `json:"stock,omitempty"` // 零值时忽略
}

3. 处理嵌套结构体

JSON 数据可以包含嵌套结构,Go 的结构体支持嵌套解析。

示例:

go
type Address struct {
	City  string `json:"city"`
	State string `json:"state"`
}

type User struct {
	Name    string  `json:"name"`
	Age     int     `json:"age"`
	Address Address `json:"address"`
}

func main() {
	jsonData := `{
		"name": "Alice",
		"age": 25,
		"address": {
			"city": "New York",
			"state": "NY"
		}
	}`
	var user User
	json.Unmarshal([]byte(jsonData), &user)
	fmt.Println(user.Address.City) // 输出: New York
}

4. 动态 JSON:使用 mapinterface{}

对于结构未知或动态的 JSON,可以使用 mapinterface{} 处理。

解析为 map[string]interface{}

go
func main() {
	jsonData := `{"name":"Alice","age":25,"skills":["Go","Python"]}`
	var data map[string]interface{}
	json.Unmarshal([]byte(jsonData), &data)

	fmt.Println(data["name"])           // 输出: Alice
	fmt.Println(data["skills"].([]interface{})) // 输出: [Go Python]
}

嵌套动态 JSON

go
func main() {
	jsonData := `{
		"user": {
			"name": "Alice",
			"age": 25
		},
		"skills": ["Go", "Python"]
	}`
	var data map[string]interface{}
	json.Unmarshal([]byte(jsonData), &data)

	user := data["user"].(map[string]interface{})
	fmt.Println(user["name"]) // 输出: Alice
}

5. 流式解析 JSON

对于大文件或 JSON 数据流,可以使用 json.Decoder 按流解析,节省内存。

示例:

go
package main

import (
	"encoding/json"
	"os"
)

func main() {
	file, _ := os.Open("data.json")
	defer file.Close()

	decoder := json.NewDecoder(file)
	for {
		var record map[string]interface{}
		if err := decoder.Decode(&record); err != nil {
			break
		}
		fmt.Println(record)
	}
}

6. 处理特殊数据类型

时间类型:time.Time

Go 的 JSON 默认不直接支持 time.Time,需要自定义格式。

go
type Event struct {
	Name      string    `json:"name"`
	Timestamp time.Time `json:"timestamp"`
}

func main() {
	event := Event{Name: "Meeting", Timestamp: time.Now()}
	jsonData, _ := json.Marshal(event)
	fmt.Println(string(jsonData)) // 输出: {"name":"Meeting","timestamp":"2025-01-01T12:00:00Z"}

	// 自定义时间格式
	type CustomEvent struct {
		Timestamp time.Time `json:"timestamp" format:"2006-01-02"`
	}
}

7. 错误处理与增强

处理错误

json.Marshaljson.Unmarshal 会返回错误,建议始终检查错误:

go
jsonData, err := json.Marshal(data)
if err != nil {
	fmt.Println("Error:", err)
}

第三方库:go-json

对于高性能场景,可以使用优化版 JSON 库(如 github.com/goccy/go-json),提供更快的序列化与反序列化。


8. JSON 对性能的影响

  • JSON 的解析和生成速度较慢,特别是在大数据场景下。
  • 如果对性能要求较高,可以考虑使用更高效的数据格式(如 Protobuf、MsgPack)。

总结

  • Go 提供了强大的 JSON 支持,适用于大多数场景。
  • 通过结构体标签可以自定义 JSON 字段行为。
  • 对于动态或复杂 JSON,可以使用 mapinterface{}
  • 在大文件或流式数据处理时,推荐使用 json.Decoder