encoding/json – Go标准库深度解析
概述
Go语言的encoding/json
包提供了对JSON数据的编码和解码功能。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,在现代Web开发和API设计中广泛使用。
核心功能
JSON编码
使用json.Marshal()
函数可以将Go数据结构转换为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}
jsonData, err := json.Marshal(p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(jsonData))
// 输出: {"name":"Alice","age":25}
}
JSON解码
使用json.Unmarshal()
函数可以将JSON数据解码为Go数据结构:
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
jsonData := []byte(`{"name":"Bob","age":30}`)
var p Person
err := json.Unmarshal(jsonData, &p)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", p)
// 输出: {Name:Bob Age:30}
}
高级特性
自定义编码/解码
通过实现json.Marshaler
和json.Unmarshaler
接口,可以自定义类型的编码和解码行为:
type CustomDate struct {
Year int
Month int
Day int
}
func (d CustomDate) MarshalJSON() ([]byte, error) {
dateStr := fmt.Sprintf(`"%d-%02d-%02d"`, d.Year, d.Month, d.Day)
return []byte(dateStr), nil
}
func (d *CustomDate) UnmarshalJSON(data []byte) error {
var dateStr string
if err := json.Unmarshal(data, &dateStr); err != nil {
return err
}
parts := strings.Split(dateStr, "-")
if len(parts) != 3 {
return fmt.Errorf("invalid date format")
}
d.Year, _ = strconv.Atoi(parts[0])
d.Month, _ = strconv.Atoi(parts[1])
d.Day, _ = strconv.Atoi(parts[2])
return nil
}
流式处理
对于大文件或网络流,可以使用json.Encoder
和json.Decoder
:
// 编码到io.Writer
func encodeToWriter(w io.Writer, data interface{}) error {
enc := json.NewEncoder(w)
return enc.Encode(data)
}
// 从io.Reader解码
func decodeFromReader(r io.Reader, v interface{}) error {
dec := json.NewDecoder(r)
return dec.Decode(v)
}
处理未知字段
使用json.RawMessage
可以延迟解码部分JSON数据:
type Message struct {
Type string `json:"type"`
Payload json.RawMessage `json:"payload"`
}
var m Message
json.Unmarshal(data, &m)
// 根据m.Type决定如何解析m.Payload
性能考虑
- 复用Encoder/Decoder:在频繁操作时,复用这些对象可以减少内存分配
- 预分配slice/map:对于大数组或对象,预分配空间可以提高性能
- 使用字节切片:避免不必要的string转换
常见错误处理
JSON标签使用
type Example struct {
Field1 string `json:"field1"` // JSON key为"field1"
Field2 string `json:"field2,omitempty"` // 如果为空则忽略此字段
Field3 string `json:"-"` // 忽略此字段
}
处理特殊值
JSON没有NaN
、Inf
等特殊数值,处理时需要特别小心:
func (f Float64) MarshalJSON() ([]byte, error) {
if math.IsNaN(float64(f)) {
return []byte(`"NaN"`), nil
}
return json.Marshal(float64(f))
}
实战建议
- 总是检查
Marshal
和Unmarshal
的错误 - 对于API响应,考虑使用自定义错误类型
- 在生产环境中,建议限制解码的最大深度和大小以防恶意输入
总结
encoding/json
包是Go语言处理JSON数据的标准方式,它提供了从简单到复杂的全方位处理能力。掌握这个包对于任何Go开发者来说都是必不可少的技能。
预告:下一期我们将深入研究net/http
包,它是Go语言构建Web服务的核心工具。