encoding/json:Go语言中的JSON编码与解码
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,因其易于阅读和编写的特性,在现代网络应用中广泛使用。Go语言的标准库encoding/json
提供了完整的JSON编码和解码功能,支持Go数据结构和JSON数据之间的相互转换。
基本使用
JSON编码(Marshal)
将Go数据结构转换为JSON字符串的过程称为”编码”或”序列化”,在encoding/json
包中通过Marshal
函数实现:
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("JSON编码错误:", err)
return
}
fmt.Println(string(data)) // 输出: {"name":"Alice","age":25}
}
JSON解码(Unmarshal)
将JSON字符串解析为Go数据结构的过程称为”解码”或”反序列化”,通过Unmarshal
函数实现:
func main() {
jsonData := `{"name":"Bob","age":30}`
var p Person
err := json.Unmarshal([]byte(jsonData), &p)
if err != nil {
fmt.Println("JSON解码错误:", err)
return
}
fmt.Printf("%+v\n", p) // 输出: {Name:Bob Age:30}
}
高级特性
结构体标签
结构体字段的标签可以控制编码过程中的JSON字段名:
type User struct {
Username string `json:"user_name"`
Password string `json:"-"` // 忽略该字段
Email string `json:"email,omitempty"` // 如果为空则忽略
}
json:"user_name"
:指定JSON字段名为”user_name”json:"-"
:完全忽略该字段json:"email,omitempty"
:如果email为空则不在JSON中输出该字段
编解码器
对于流式数据或需要更细致控制的情况,可以使用json.Encoder
和json.Decoder
:
func streamExample() {
// 编码器示例
data := Person{Name: "Charlie", Age: 35}
enc := json.NewEncoder(os.Stdout)
enc.Encode(data) // 直接输出到标准输出
// 解码器示例
input := `{"name":"Dave","age":40}`
dec := json.NewDecoder(strings.NewReader(input))
var p Person
dec.Decode(&p)
fmt.Printf("%+v\n", p)
}
处理动态JSON
处理未知结构的JSON数据时,可以使用map[string]interface{}
或json.RawMessage
:
func handleDynamicJSON() {
data := `{"name":"Eve","age":45,"hobbies":["reading","swimming"]}`
var result map[string]interface{}
json.Unmarshal([]byte(data), &result)
age := result["age"].(float64) // JSON数字默认转为float64
fmt.Println(age)
hobbies := result["hobbies"].([]interface{})
for _, h := range hobbies {
fmt.Println(h.(string))
}
}
性能优化
复用解码器
var decoderPool = sync.Pool{
New: func() interface{} {
return json.NewDecoder(nil)
},
}
func decodeWithPool(data []byte, v interface{}) error {
dec := decoderPool.Get().(*json.Decoder)
defer decoderPool.Put(dec)
dec.Reset(bytes.NewReader(data))
return dec.Decode(v)
}
使用jsoniter
虽然jsoniter不是标准库的一部分,但它提供了更快的JSON处理速度:
import "github.com/json-iterator/go"
var jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
func useJsonIter() {
data, _ := jsonIter.Marshal(&Person{Name: "Frank", Age: 50})
var p Person
jsonIter.Unmarshal(data, &p)
}
常见问题
- 字段可见性问题:只有首字母大写的字段才会被编码/解码
- 零值处理:数字0、空字符串等在JSON中会被编码
- 自定义编解码:通过实现
json.Marshaler
和json.Unmarshaler
接口可以自定义编解码行为
type CustomTime time.Time
func (ct *CustomTime) UnmarshalJSON(data []byte) error {
// 自定义时间解析逻辑
}
func (ct CustomTime) MarshalJSON() ([]byte, error) {
// 自定义时间格式化为JSON
}
总结
encoding/json
包提供了Go语言与JSON数据交互的完整功能集。通过掌握基本编码解码、结构体标签、流式处理和动态JSON等特性,可以高效地在Go程序中处理JSON数据。对于性能敏感的场景,可以考虑使用对象池或替代实现如jsoniter。
文末预告:下一期我们将深入学习net/http
包——Go语言中构建HTTP服务与客户端的核心工具。