encoding/json 库深度解析
1. 简介
标准库中的encoding/json
包提供了对JSON数据的编码和解码功能,是Go语言中处理JSON数据最常用的工具之一。它可以实现Go数据结构和JSON之间的相互转换,支持基本的序列化和反序列化操作。
2. 核心功能
2.1 JSON编码(Marshal)
将Go数据结构转换为JSON字符串:
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
p := Person{Name: "Alice", Age: 25}
jsonData, err := json.Marshal(p)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(jsonData)) // 输出: {"name":"Alice","age":25}
}
2.2 JSON解码(Unmarshal)
将JSON字符串解析为Go数据结构:
jsonStr := `{"name":"Bob","age":30}`
var p Person
err := json.Unmarshal([]byte(jsonStr), &p)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", p) // 输出: {Name:Bob Age:30}
2.3 流式处理(Encoder/Decoder)
对于大文件或网络流的处理,可以使用流式API:
// 流式编码
func encodeToStream(w io.Writer, data interface{}) error {
enc := json.NewEncoder(w)
return enc.Encode(data)
}
// 流式解码
func decodeFromStream(r io.Reader, v interface{}) error {
dec := json.NewDecoder(r)
return dec.Decode(v)
}
3. 高级特性
3.1 结构体标签控制
通过结构体标签可以控制JSON编码/解码的行为:
type User struct {
ID int `json:"id,omitempty"`
Username string `json:"username"`
Password string `json:"-"` // 忽略该字段
Roles []string `json:"roles,omitempty"` // 如果为空则忽略
}
3.2 自定义Marshal/Unmarshal
实现json.Marshaler
和json.Unmarshaler
接口可以进行自定义序列化:
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
}
func (ct *CustomTime) UnmarshalJSON(data []byte) error {
// 自定义解析逻辑
}
3.3 处理未知字段
使用json.RawMessage
延迟解析或在Unmarshal时使用map[string]interface{}
:
var data map[string]interface{}
json.Unmarshal(jsonData, &data)
// 或者
type Message struct {
Body json.RawMessage // 延迟解析
Extras map[string]interface{} // 存储未知字段
}
4. 性能优化
4.1 复用Encoder/Decoder
对于高频使用的场景,可以复用Encoder和Decoder:
var enc = json.NewEncoder(os.Stdout)
for _, v := range values {
if err := enc.Encode(v); err != nil {
log.Println(err)
}
}
4.2 使用jsoniter等第三方库
对于极致性能要求,可以考虑使用jsoniter
等第三方库:
import jsoniter "github.com/json-iterator/go"
var json = jsoniter.ConfigCompatibleWithStandardLibrary
5. 常见陷阱
5.1 循环引用
处理包含循环引用的数据结构时需要小心:
type Node struct {
Value int
Children []*Node
}
// 解决方案: 使用ID引用或实现自定义序列化
5.2 NaN/Infinity处理
JSON规范不支持NaN和Infinity,需要特殊处理:
func (f Float64) MarshalJSON() ([]byte, error) {
if math.IsNaN(float64(f)) {
return []byte(`"NaN"`), nil
}
// ...
}
5.3 指针字段
指针字段为nil时会被编码为null,而非零值:
type Container struct {
Value *int `json:"value"`
}
6. 总结
encoding/json
是Go语言中处理JSON数据的核心库,提供了丰富的功能和灵活的配置选项。掌握它的使用技巧可以有效提升开发效率和程序性能。
文末预告:下一期我们将深入学习net/http
库,详细介绍如何使用Go语言构建HTTP服务器和客户端。