如何在 Go 中正确使用 JSON 序列化结构体切片

11次阅读

如何在 Go 中正确使用 JSON 序列化结构体切片

go 的 `json.marshal` 默认仅导出首字母大写的字段;若结构体字段为小写(未导出),序列化结果将为空对象,需通过标签和导出字段确保数据正确输出。

go 中,jsON 编码(marshalling)遵循严格的可见性规则:只有导出字段(即首字母大写的字段)才能被 encoding/json 包访问并序列化。你定义的 SpanInfo 结构体中所有字段均为小写(如 imsi、network),属于未导出字段,因此 json.Marshal 无法读取其值,最终生成 [{},{},{},{}] 这样的空对象数组。

要解决此问题,需两步改造:

  1. 将字段名改为首字母大写,使其可导出
  2. 配合 json 标签(tag)指定序列化后的键名,保持 JSON 字段命名风格(如 snake_case)不变。

修正后的结构体定义如下:

type SpanInfo struct {     IMSI         string `json:"imsi"`     Network      string `json:"network"`     NetworkStatus string `json:"network_status"`     SignalQuality int    `json:"signal_quality"`     Slot         int    `json:"slot"`     State        string `json:"state"` }  type gatewayInfo []SpanInfo

此时,即使 GatewayInfo 是类型别名([]SpanInfo),只要其元素类型 SpanInfo 的字段已正确导出并标注,json.Marshal 即可完整序列化整个切片

func getGatewayInfo(spans []SpanInfo) GatewayInfo {     return GatewayInfo(spans) }  // 使用示例 gatewayInfo := getGatewayInfo([]SpanInfo{     {IMSI: "652020105829193", Network: "20801", NetworkStatus: "Registered (Roaming)", SignalQuality: 17, Slot: 2, State: "active"},     {IMSI: "652020105829194", Network: "20801", NetworkStatus: "Registered (Roaming)", SignalQuality: 16, Slot: 3, State: "standby"}, })  data, err := json.Marshal(gatewayInfo) if err != nil {     log.Fatal(err) } log.Printf("JSON output: %s", data) // 输出示例: // [{"imsi":"652020105829193","network":"20801","network_status":"Registered (Roaming)","signal_quality":17,"slot":2,"state":"active"}, ...]

⚠️ 注意事项:

  • 若字段无需出现在 JSON 中,可添加 json:”-” 标签忽略;
  • 若希望零值字段(如空字符串、0)不输出,可追加 ,omitempty(例如 json:”imsi,omitempty”);
  • 切片本身无需额外导出——GatewayInfo 是类型别名而非结构体,其序列化行为完全取决于 SpanInfo 字段的导出状态与标签配置。

总结:Go 的 JSON 序列化是“导出即可见”,小写字段等于对 encoding/json 不可见。务必统一使用大写首字母 + json 标签,这是实现可控、可读、符合 API 规范的 JSON 输出的基础实践。

text=ZqhQzanResources