Golang中json序列化与反序列化

Golang JSON 序列化与反序列化详解

Go语言提供了强大的标准库支持JSON的序列化(编码)和反序列化(解码)。以下是详细的使用方法和示例。

基本概念

  • 序列化(编码):将Go的数据结构转换为JSON字符串
  • 反序列化(解码):将JSON字符串转换为Go的数据结构

1. 基本的序列化和反序列化

定义结构体

type Person struct {
    Name   string `json:"name"`
    Age    int    `json:"age"`
    Email  string `json:"email,omitempty"` // omitempty表示如果为空则省略
    Secret string `json:"-"`               // - 表示不序列化该字段
}

序列化示例

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

func main() {
    // 创建Person实例
    person := Person{
        Name:   "张三",
        Age:    30,
        Email:  "zhangsan@example.com",
        Secret: "不显示的秘密",
    }

    // 序列化为JSON
    jsonData, err := json.Marshal(person)
    if err != nil {
        log.Fatal("序列化失败:", err)
    }
  
    fmt.Println(string(jsonData))
    // 输出: {"name":"张三","age":30,"email":"zhangsan@example.com"}
}

格式化序列化

// 使用MarshalIndent生成格式化的JSON
jsonData, err := json.MarshalIndent(person, "", "  ")
if err != nil {
    log.Fatal("序列化失败:", err)
}
fmt.Println(string(jsonData))

反序列化示例

func main() {
    jsonStr := `{"name":"李四","age":25,"email":"lisi@example.com"}`
  
    var person Person
    err := json.Unmarshal([]byte(jsonStr), &person)
    if err != nil {
        log.Fatal("反序列化失败:", err)
    }
  
    fmt.Printf("姓名: %s, 年龄: %d, 邮箱: %s\n", person.Name, person.Age, person.Email)
}

2. 处理复杂数据结构

嵌套结构体

type Address struct {
    City    string `json:"city"`
    Country string `json:"country"`
}

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

func nestedExample() {
    user := User{
        Name: "王五",
        Age:  28,
        Address: Address{
            City:    "北京",
            Country: "中国",
        },
    }
  
    jsonData, _ := json.MarshalIndent(user, "", "  ")
    fmt.Println(string(jsonData))
}

切片和映射

func sliceMapExample() {
    // 切片序列化
    names := []string{"Alice", "Bob", "Charlie"}
    namesJSON, _ := json.Marshal(names)
    fmt.Println("切片:", string(namesJSON))
  
    // 映射序列化
    data := map[string]interface{}{
        "name":  "张三",
        "age":   30,
        "hobbies": []string{"阅读", "游泳", "编程"},
    }
    mapJSON, _ := json.MarshalIndent(data, "", "  ")
    fmt.Println("映射:", string(mapJSON))
  
    // 反序列化到映射
    var result map[string]interface{}
    json.Unmarshal(mapJSON, &result)
    fmt.Println("反序列化结果:", result)
}

3. 自定义序列化和反序列化

实现json.Marshaler接口

type CustomDate struct {
    Year  int
    Month int
    Day   int
}

// 实现MarshalJSON方法
func (d CustomDate) MarshalJSON() ([]byte, error) {
    dateStr := fmt.Sprintf("\"%d-%02d-%02d\"", d.Year, d.Month, d.Day)
    return []byte(dateStr), nil
}

// 实现UnmarshalJSON方法
func (d *CustomDate) UnmarshalJSON(data []byte) error {
    var dateStr string
    if err := json.Unmarshal(data, &dateStr); err != nil {
        return err
    }
  
    _, err := fmt.Sscanf(dateStr, "%d-%d-%d", &d.Year, &d.Month, &d.Day)
    return err
}

type Event struct {
    Title string     `json:"title"`
    Date  CustomDate `json:"date"`
}

func customExample() {
    event := Event{
        Title: "生日派对",
        Date:  CustomDate{2023, 12, 25},
    }
  
    jsonData, _ := json.Marshal(event)
    fmt.Println("自定义序列化:", string(jsonData))
  
    // 反序列化
    var newEvent Event
    json.Unmarshal(jsonData, &newEvent)
    fmt.Printf("反序列化: %+v\n", newEvent)
}

4. 处理未知结构的JSON

func unknownStructure() {
    jsonStr := `{
        "name": "张三",
        "age": 30,
        "metadata": {
            "department": "技术部",
            "role": "工程师"
        }
    }`
  
    var data map[string]interface{}
    json.Unmarshal([]byte(jsonStr), &data)
  
    // 类型断言获取值
    name := data["name"].(string)
    age := data["age"].(float64) // JSON数字默认转为float64
  
    fmt.Printf("姓名: %s, 年龄: %.0f\n", name, age)
  
    // 处理嵌套对象
    metadata := data["metadata"].(map[string]interface{})
    department := metadata["department"].(string)
    fmt.Println("部门:", department)
}

5. 流式处理(处理大文件)

func streamExample() {
    // 模拟从文件或网络流读取JSON
    jsonStream := `{"name":"用户1","age":25}
{"name":"用户2","age":30}
{"name":"用户3","age":35}`
  
    decoder := json.NewDecoder(strings.NewReader(jsonStream))
  
    for {
        var person Person
        if err := decoder.Decode(&person); err == io.EOF {
            break // 流结束
        } else if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("处理用户: %+v\n", person)
    }
}

6. 错误处理最佳实践

func safeUnmarshal() {
    jsonStr := `{"name":"张三","age":"三十"}` // 错误的age类型
  
    var person Person
    if err := json.Unmarshal([]byte(jsonStr), &person); err != nil {
        if jsonErr, ok := err.(*json.UnmarshalTypeError); ok {
            fmt.Printf("类型错误: 字段 %s 期望类型 %s, 实际值: %s\n",
                jsonErr.Field, jsonErr.Type, jsonErr.Value)
        } else {
            fmt.Printf("JSON解析错误: %v\n", err)
        }
        return
    }
    fmt.Printf("成功: %+v\n", person)
}

7. 性能优化技巧

使用json.RawMessage延迟解析

type Message struct {
    Type string          `json:"type"`
    Data json.RawMessage `json:"data"` // 原始JSON数据,延迟解析
}

func rawMessageExample() {
    jsonStr := `{
        "type": "user",
        "data": {"name":"张三","age":30}
    }`
  
    var msg Message
    json.Unmarshal([]byte(jsonStr), &msg)
  
    switch msg.Type {
    case "user":
        var user Person
        json.Unmarshal(msg.Data, &user)
        fmt.Println("用户数据:", user)
    case "product":
        // 解析为产品数据结构
    }
}

总结

Go语言的JSON处理非常强大和灵活,主要特点包括:

  1. 简单易用:通过结构体tag轻松控制序列化行为
  2. 类型安全:编译时类型检查
  3. 高性能:标准库经过高度优化
  4. 灵活性:支持自定义序列化逻辑

在实际开发中,建议:

  • 始终处理错误
  • 对于大型数据使用流式处理
  • 使用omitempty避免空值污染JSON输出
  • 对于复杂场景考虑实现自定义的Marshaler/Unmarshaler接口
posted @ 2026-01-13 07:37  shuix1ng  阅读(8)  评论(0)    收藏  举报