Go中两种结构体声明方式JSON序列化结果差异原因咨询
问题
在Go语言中,我尝试通过将JSON反序列化为仅包含所需字段的结构体,再重新序列化为JSON来保留目标字段:
- 使用
i := DBBatch{}声明变量时,输出JSON仅保留所需字段:
{ "field_to_keep": "XXXXX", "field_to_keep2": "26400527" }
- 但使用
var i interface{} = DBBatch{}声明时,输出JSON仍存在冗余字段:
{ "field_to_delete": "whynotdeleted", "field_to_keep": "XXXXX", "field_to_keep2": "26400527" }
我原以为这两种声明只是语法糖,效果一致,想请教为何输出结果不同?
相关示例代码如下:
package main import ( "encoding/json" "log" ) type DBBatch struct { FieldtoKeep string `json:"field_to_keep"` FieldtoKeep2 string `json:"field_to_keep2"` } func main() { jsonBatch := `{"field_to_keep":"XXXXX","field_to_keep2":"26400527","field_to_delete":"whynotdeleted"}` var i interface{} = DBBatch{} //i := DBBatch{} if err := json.Unmarshal([]byte(jsonBatch), &i); err != nil { log.Println("json UnMarshal from batch json failed") log.Println(err) } dbJsonBatch, err := json.Marshal(i) if err != nil { log.Println("json Marshal from batch json failed") log.Println(err) } log.Println("json Marshal from maps of key string and value interface to batch json for insert to DB") log.Println(string(dbJsonBatch)) pp, _ := json.MarshalIndent(i, "", " ") log.Println(string(pp)) }
原因分析
这两种声明的核心差异在于**json.Unmarshal接收的指针类型不同**,导致反序列化逻辑完全不一样:
- 当使用
i := DBBatch{}时,&i的类型是*DBBatch。json.Unmarshal会严格按照结构体的字段标签解析JSON,只匹配目标字段,自动忽略冗余的field_to_delete。后续json.Marshal时,仅序列化结构体中定义的字段,因此输出无冗余内容。 - 当使用
var i interface{} = DBBatch{}时,&i的类型是*interface{}。此时json.Unmarshal会将JSON对象解析为map[string]interface{}(这是Go对JSON对象的默认解析类型),并将这个完整包含所有字段的map赋值给i,直接覆盖了原来的DBBatch实例。后续json.Marshal序列化的是这个完整map,自然会保留所有冗余字段。
简单来说:前者是反序列化到结构体,后者是反序列化为map并替换了原变量,最终序列化的对象本质完全不同。
内容的提问来源于stack exchange,提问作者echo
相关产品推荐
相关产品推荐

