You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 20:05:01