Go 中 JSON 反序列化失败:结构体字段未导出导致解析为空值

go 的 `json.unmarshal` 要求结构体字段必须首字母大写(即导出字段),否则无法访问并赋值,即使无报错也会返回零值。

在 Go 中,encoding/json 包通过反射机制读取和设置结构体字段,但仅能操作导出(exported)字段——即字段名首字母为大写字母。若字段以小写开头(如 status、entryCount),则属于包内私有字段,json 包无法访问,因此反序列化时跳过这些字段,保留其零值(如空字符串 ""、0、false 或 nil 切片),且不返回错误。

你原始代码中的结构体定义存在两个关键问题:

  1. 所有字段均为非导出字段(全小写),json 包完全不可见;
  2. 字段名与 JSON 键名不匹配,需通过结构体标签(struct tags)显式映射。

✅ 正确做法如下:

  • 将字段名改为 PascalCase(首字母大写)以导出;
  • 使用 json:"key" 标签精确对应 JSON 中的键名(注意大小写和拼写,例如 "deprecated" 不是 "depricated");
  • 建议同时导出嵌套结构体(如 Meta、Status),便于复用和调试。

以下是修复后的完整示例:

package main

import (
    "encoding/json"
    "fmt"
)

type Status struct {
    NodeID string `json:"node_id"`
    Status string `json:"status"`
}

type Meta struct {
    ID         string `json:"id"`
    From       string `json:"from"`
    To         string `json:"to"`
    EntryCount int64  `json:"entryCount"`
    Size       int64  `json:"size"`
    Deprecated bool   `json:"deprecated"` // 注意:原文本中为 "deprecated",非 "depricated"
}

type MyData struct {
    Metadata Meta    `json:"metadata"`
    Status   []Status `json:"status"`
}

func main() {
    jsonData := `{
        "metadata":{
            "id":"2377f625-619b-4e20-90af-9a6cbfb80040",
            "from":"2014-12-30T07:23:42.000Z",
            "to":"2015-01-14T05:11:51.000Z",
            "entryCount":801,
            "size":821472,
            "deprecated":false
        },
        "status":[{ "node_id":"de713614-be3d-4c39-a3f8-1154957e46a6", "status":"PUBLISHED" }]
    }`

    var data MyData
    err := json.Unmarshal([]byte(jsonData), &data)
    if err != nil {
        fmt.Printf("JSON 解析错误: %v\n", err)
        return
    }

    fmt.Printf("解析成功: %+v\n", data)
    // 输出示例:
    // 解析成功: {Metadata:{ID:"2377f625-619b-4e20-90af-9a6cbfb80040" From:"2014-12-30T07:23:42.000Z" To:"2015-01-14T05:11:51.000Z" EntryCount:801 Size:821472 Deprecated:false} Status:[{NodeID:"de713614-be3d-4c39-a3f8-1154957e46a6" Status:"PUBLISHED"}]}
}

⚠️ 注意事项:

  • 字段拼写务必准确:"deprecated" ≠ "depricated"(原答案中 Depricated 是笔误,应修正为 Deprecated);
  • Node_id 在 JSON 中是蛇形命名,Go 中推荐使用 NodeID(驼峰)+ json:"node_id" 标签,符合 Go 命名惯例;
  • 若需兼容多种 JSON 格式(如不同环境返回不同键名),可添加多个 json 标签(如 json:",omitempty" 控制零值省略);
  • 开发时建议开启 go vet 或使用 staticcheck 等工具,它们能检测到未导出字段导致的 JSON 序列化失效问题。

总结:Go 的 JSON 反序列化不是“尽力而为”,而是严格依赖导出性与标签匹配。牢记 —— 小写 = 私有 = JSON 不可见,这是新手最常踩的隐性陷阱。