Go语言JSON序列化时如何显示空对象而非空结构体或nil
解决Go中结构体指针序列化为JSON空对象{}的问题
这个问题我之前也碰到过,Go标准库的json.Marshal默认行为确实会让人有点头疼——未初始化的指针输出null,初始化的空结构体又会把零值字段都打出来。不过有两种靠谱的解决办法,你可以根据自己的需求选:
方案一:给结构体字段加omitempty标签(最简单)
这是最直接的办法,只要给Person结构体的每个字段加上json:"字段名,omitempty"标签,当字段是零值时就会被序列化器忽略,最终空结构体就会变成{}。
示例代码:
package main import ( "encoding/json" "fmt" "log" "time" ) type Person struct { Name string `json:"name,omitempty"` // 加omitempty标签 Age int `json:"age,omitempty"` // 加omitempty标签 } type Response struct { Data struct { Person *Person `json:"person"` CreatedDate time.Time `json:"created_date"` } `json:"data"` } func main() { resp := Response{ Data: struct { Person *Person `json:"person"` CreatedDate time.Time `json:"created_date"` }{ Person: &Person{}, // 初始化空结构体 CreatedDate: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), }, } data, err := json.Marshal(resp) if err != nil { log.Fatal(err) } fmt.Println(string(data)) // 输出:{"data":{"person":{},"created_date":"2009-11-10T23:00:00Z"}} }
这个方案的好处是代码改动极小,适合大多数场景。但如果你有需求要保留某些零值字段(比如Age为0是有意义的,不能忽略),那可以看第二种方案。
方案二:自定义JSON序列化逻辑
通过让*Person实现json.Marshaler接口,我们可以完全控制它的序列化行为——不管指针是nil还是指向零值结构体,都输出{},有非零值时再正常序列化。
示例代码:
package main import ( "encoding/json" "fmt" "log" "time" ) type Person struct { Name string `json:"name"` Age int `json:"age"` } // 给*Person实现MarshalJSON方法 func (p *Person) MarshalJSON() ([]byte, error) { // 情况1:指针为nil,直接返回{} if p == nil { return []byte("{}"), nil } // 情况2:结构体是零值,返回{} if p.Name == "" && p.Age == 0 { return []byte("{}"), nil } // 情况3:有非零值,正常序列化(用Alias避免递归调用) type Alias Person return json.Marshal((*Alias)(p)) } type Response struct { Data struct { Person *Person `json:"person"` CreatedDate time.Time `json:"created_date"` } `json:"data"` } func main() { // 测试空结构体指针 resp1 := Response{ Data: struct { Person *Person `json:"person"` CreatedDate time.Time `json:"created_date"` }{ Person: &Person{}, CreatedDate: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), }, } data1, _ := json.Marshal(resp1) fmt.Println(string(data1)) // 输出:{"data":{"person":{},"created_date":"2009-11-10T23:00:00Z"}} // 测试nil指针 resp2 := Response{ Data: struct { Person *Person `json:"person"` CreatedDate time.Time `json:"created_date"` }{ Person: nil, CreatedDate: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), }, } data2, _ := json.Marshal(resp2) fmt.Println(string(data2)) // 输出:{"data":{"person":{},"created_date":"2009-11-10T23:00:00Z"}} // 测试有值的结构体 resp3 := Response{ Data: struct { Person *Person `json:"person"` CreatedDate time.Time `json:"created_date"` }{ Person: &Person{Name: "Alice", Age: 30}, CreatedDate: time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), }, } data3, _ := json.Marshal(resp3) fmt.Println(string(data3)) // 输出:{"data":{"person":{"name":"Alice","age":30},"created_date":"2009-11-10T23:00:00Z"}} }
这个方案更灵活,能区分“零值结构体”和“有意义的零值”场景,适合复杂的业务需求。
内容的提问来源于stack exchange,提问作者tama
相关产品推荐
相关产品推荐

