贝利信息

Go语言中JSON序列化时结构体字段必须导出才能生效

日期:2026-01-18 00:00 / 作者:花韻仙語

在go中使用json.marshal序列化结构体切片时,若json输出为空对象(如[{},{}]),根本原因是结构体字段未导出(即首字母小写),导致json包无法访问这些字段。解决方法是将字段名首字母大写并合理使用json标签。

Go 的 encoding/json 包遵循严格的可见性规则:只有导出(exported)字段(即首字母大写的字段)才能被 JSON 编码/解码器访问。你原始定义中的 imsi、network 等字段均为小写开头,属于未导出字段,因此 json.Marshal 会忽略它们,仅生成空的 JSON 对象 {}。

✅ 正确做法如下:

  1. 将结构体字段首字母大写,使其导出;
  2. 通过 json struct tag 显式指定 JSON 键名,保持与预期的 JSON 字段命名一致(如使用下划线风格);
  3. (可选)为字段添加 omitempty 标签避免零值冗余输出。

修正后的类型定义示例:

type SpanInfo struct {
    IMSI          string `json:"imsi"`
    Network       string `json:"network"`
    NetworkStatus string `json:"network_status"`
    SignalQuality int    `json:"signal_quali

ty"` Slot int `json:"slot"` State string `json:"state"` } type GatewayInfo []SpanInfo

使用方式保持不变:

func getGatewayInfo(spans []SpanInfo) GatewayInfo {
    return GatewayInfo(spans)
}

// 示例初始化
spans := []SpanInfo{
    {IMSI: "652025105829193", Network: "20801", NetworkStatus: "Registered (Roaming)", SignalQuality: 17, Slot: 2, State: "active"},
    {IMSI: "652025105829194", Network: "20801", NetworkStatus: "Registered (Roaming)", SignalQuality: 16, Slot: 3, State: "active"},
}
gatewayInfo := getGatewayInfo(spans)

jsonInfo, err := json.Marshal(gatewayInfo)
if err != nil {
    log.Fatal("JSON marshal error:", err)
}
log.Printf("jsonInfo: %s", jsonInfo)
// 输出示例:
// [{"imsi":"652025105829193","network":"20801","network_status":"Registered (Roaming)","signal_quality":17,"slot":2,"state":"active"},...]

⚠️ 注意事项:

总结:Go 的 JSON 序列化不是“自动反射所有字段”,而是基于导出性 + struct tag 的显式契约。养成从设计阶段就规范字段命名与标签的习惯,是写出健壮序列化逻辑的关键前提。