encoding/json:Go语言的JSON编解码利器
概述
encoding/json
是Go语言标准库中处理JSON数据的核心包,提供了JSON的编码(序列化)和解码(反序列化)功能。无论是Web开发还是其他需要数据交换的场景,这个包都发挥着重要作用。
基本功能
JSON编码
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
p := Person{Name: "Alice", Age: 25}
data, err := json.Marshal(p)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(string(data)) // 输出:{"name":"Alice","age":25}
}
JSON解码
func main() {
jsonStr := `{"name":"Bob","age":30}`
var p Person
err := json.Unmarshal([]byte(jsonStr), &p)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("%+v\n", p) // 输出:{Name:Bob Age:30}
}
高级特性
结构体标签
json:"..."
结构体标签提供了对JSON字段名的精细控制:
type User struct {
ID int `json:"user_id"`
Name string `json:"full_name"`
Password string `json:"-"` // 忽略此字段
private bool `json:"private"` // 非导出字段会被忽略
}
自定义编解码
对于需要定制序列化行为的类型,可以实现json.Marshaler
和json.Unmarshaler
接口:
type CustomTime struct {
time.Time
}
func (ct *CustomTime) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%s"`, ct.Format("2006-01-02"))), nil
}
func (ct *CustomTime) UnmarshalJSON(data []byte) error {
s := strings.Trim(string(data), `"`)
t, err := time.Parse("2006-01-02", s)
if err != nil {
return err
}
ct.Time = t
return nil
}
解码到interface{}
func main() {
var data interface{}
jsonStr := `{"name":"Charlie","details":{"age":40,"hobby":"coding"}}`
err := json.Unmarshal([]byte(jsonStr), &data)
if err != nil {
fmt.Println("Error:", err)
return
}
m := data.(map[string]interface{})
fmt.Println(m["name"]) // 输出:Charlie
fmt.Println(m["details"].(map[string]interface{})["age"]) // 输出:40
}
流式处理
json.NewEncoder
和json.NewDecoder
提供了基于流的处理方式:
func main() {
p := Person{Name: "Dave", Age: 35}
// 写入输出流
var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
encoder.Encode(p)
fmt.Println(buf.String())
// 从输入流读取
decoder := json.NewDecoder(&buf)
var newP Person
decoder.Decode(&newP)
fmt.Printf("%+v\n", newP)
}
性能优化
- 预分配缓冲区:当已知JSON数据大致大小时
- 复用编码器/解码器:减少内存分配
- 避免反射:对于高性能需求场景,考虑使用代码生成工具如
easyjson
常见陷阱
- 循环引用:结构体之间相互引用会导致
Marshal
无限循环 - 指针字段:带
nil
指针的字段可能会被编码为null
- 精度丢失:使用
float64
表示大整数时可能出现精度问题
总结
encoding/json
包提供了强大而灵活的JSON处理能力,适合大多数Go应用的JSON数据交换需求。理解其内部实现原理和性能特性,可以帮助开发者编写出更高效、更健壮的代码。
文末预告:下一期我们将深入探讨net/http
包,解析Go语言强大的HTTP服务器和客户端实现机制。