Golang通过encoding/json包利用结构体标签实现JSON序列化与反序列化,支持字段映射、忽略、omitempty省略零值、string字符串转换等标签用法,并可通过json.RawMessage、map[string]interface{}、自定义接口及流式处理等方式灵活应对数据结构不匹配与性能优化需求。

Golang处理JSON数据,其核心机制在于
encoding/json
json:"..."
Go语言在处理JSON数据方面,提供了一套既简洁又强大的工具集,主要通过标准库的
encoding/json
我们先从最常见的场景说起:将一个Go结构体转换成JSON字符串,以及将JSON字符串解析回Go结构体。
当你有一个Go结构体实例,想把它变成JSON格式,通常会用到
json.Marshal()
立即学习“go语言免费学习笔记(深入)”;
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email,omitempty"`
CreatedAt string `json:"created_at,string"` // 示例:日期通常是字符串
Password string `json:"-"` // 这个字段不想暴露到JSON中
}
func main() {
user := User{
ID: 1,
Username: "gopher",
Email: "gopher@example.com",
CreatedAt: "2023-10-27T10:00:00Z",
Password: "very-secret",
}
jsonData, err := json.Marshal(user)
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return
}
fmt.Println(string(jsonData))
// 预期输出:{"id":1,"username":"gopher","email":"gopher@example.com","created_at":"2023-10-27T10:00:00Z"}
}这里,
json:"id"
Marshal
ID
ID
omitempty
json:"-"
Marshal
Password
反过来,如果是将JSON字符串解析回Go结构体,我们用的是
json.Unmarshal()
jsonString := `{"id":2,"username":"json_user","created_at":"2023-10-27T11:00:00Z"}`
var newUser User
err := json.Unmarshal([]byte(jsonString), &newUser)
if err != nil {
fmt.Println("Error unmarshaling JSON:", err)
return
}
fmt.Printf("User: %+v\n", newUser)
// 预期输出:User: {ID:2 Username:json_user Email: CreatedAt:2023-10-27T11:00:00Z Password:}注意到,JSON字符串中没有
Password
Password
json
json
json:"fieldName"
UserName
user_name
json:"user_name"
encoding/json
UserName
UserName
type Product struct {
ProductName string `json:"product_name"` // JSON中是product_name
Price float64 `json:"price"`
}json:"-"
type Config struct {
APIKey string `json:"api_key"`
SecretKey string `json:"-"` // 永远不序列化或反序列化
}json:",omitempty"
encoding/json
""
0
false
nil
nil
type UserProfile struct {
Name string `json:"name"`
Age int `json:"age,omitempty"` // 如果age是0,则省略
Address *string `json:"address,omitempty"` // 如果address是nil,则省略
}如果
Age
Address
nil
json:",string"
type Item struct {
ItemID int64 `json:"item_id,string"` // 在JSON中会是"12345"而不是12345
}这些标签可以组合使用,例如
json:"field_name,omitempty,string"
在实际开发中,我们经常会遇到JSON数据结构与Go结构体定义不完全匹配的情况,比如JSON中多了几个字段,或者某个字段的类型可能不确定。Go的
encoding/json
忽略多余字段,匹配现有字段:这是最基础也是最常用的行为。当JSON数据包含Go结构体中没有定义的字段时,
json.Unmarshal
type SimpleUser struct {
Name string `json:"name"`
Age int `json:"age"`
}
jsonStr := `{"name":"Alice","age":30,"city":"New York"}` // JSON有多余的city字段
var user SimpleUser
json.Unmarshal([]byte(jsonStr), &user)
fmt.Printf("%+v\n", user) // 输出: {Name:Alice Age:30},city被忽略json.RawMessage
json.RawMessage
type Event struct {
EventType string `json:"event_type"`
Payload json.RawMessage `json:"payload"` // 原始JSON字节
}
type UserCreatedPayload struct {
UserID string `json:"user_id"`
Username string `json:"username"`
}
jsonEvent := `{"event_type":"user_created","payload":{"user_id":"123","username":"bob"}}`
var event Event
json.Unmarshal([]byte(jsonEvent), &event)
fmt.Printf("Event Type: %s\n", event.EventType)
if event.EventType == "user_created" {
var userPayload UserCreatedPayload
json.Unmarshal(event.Payload, &userPayload)
fmt.Printf("User Payload: %+v\n", userPayload)
}map[string]interface{}
map[string]interface{}jsonDynamic := `{"id":1,"data":{"key1":"value1","key2":123}}`
var data map[string]interface{}
json.Unmarshal([]byte(jsonDynamic), &data)
fmt.Printf("Dynamic Data: %+v\n", data)
// 访问嵌套数据
if nestedData, ok := data["data"].(map[string]interface{}); ok {
fmt.Println("Nested Key1:", nestedData["key1"])
}实现json.Marshaler
json.Unmarshaler
MarshalJSON() ([]byte, error)
UnmarshalJSON([]byte) error
type CustomDate struct {
time.Time
}
func (cd *CustomDate) UnmarshalJSON(b []byte) error {
s := strings.Trim(string(b), `"`) // 移除JSON字符串的引号
t, err := time.Parse("2006-01-02", s) // 自定义日期格式
if err != nil {
return err
}
cd.Time = t
return nil
}
func (cd CustomDate) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%s"`, cd.Format("2006-01-02"))), nil
}
type EventWithDate struct {
Name string `json:"name"`
Date CustomDate `json:"event_date"`
}
jsonDate := `{"name":"Meeting","event_date":"2023-10-27"}`
var eventDate EventWithDate
json.Unmarshal([]byte(jsonDate), &eventDate)
fmt.Printf("Event with Custom Date: %+v\n", eventDate)这种方式虽然提供了最大灵活性,但也会增加代码的复杂性,通常在其他方法无法满足需求时才考虑使用。
通过这些机制,Go语言提供了一个灵活且强大的框架来处理各种JSON数据结构,无论是简单的匹配还是复杂的自定义逻辑,都能找到合适的解决方案。
尽管Go的
encoding/json
避免重复的Marshal
Unmarshal
[]byte
json.RawMessage
json.RawMessage
RawMessage
Unmarshal
json.Decoder
json.Encoder
ioutil.ReadAll
json.NewDecoder
json.Encoder
io.Reader
io.Writer
// 示例:从HTTP请求体中流式读取JSON
func handleRequest(w http.ResponseWriter, r *http.Request) {
var data MyStruct
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&data)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// ... 处理data ...
}sync.Pool
json.Encoder
json.Decoder
json.Encoder
json.Decoder
sync.Pool
bytes.Buffer
sync.Pool
字段顺序和内存对齐:虽然这不是
json
避免使用interface{}
map[string]interface{}json.Marshaler
json.Unmarshaler
选择合适的JSON库:对于绝大多数应用,Go标准库的
encoding/json
jsoniter
ffjson
go test -bench
go test -bench=. -benchmem
通过基准测试,你可以量化不同方案的性能差异,从而做出明智的决策。
处理JSON数据时,性能优化往往是一个权衡的过程。我们应该在代码可读性、维护性和实际性能需求之间找到一个平衡点,而不是盲目地追求极致性能。大多数情况下,遵循上述最佳实践,标准库就能满足我们的需求。
以上就是Golang处理JSON数据 结构体标签与序列化的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号