
在go中使用json.marshal序列化结构体切片时,若json输出为空对象(如[{},{}]),根本原因是结构体字段未导出(即首字母小写),导致json包无法访问这些字段。解决方法是将字段名首字母大写并合理使用json标签。
Go 的 encoding/json 包遵循严格的可见性规则:只有导出(exported)字段(即首字母大写的字段)才能被 JSON 编码/解码器访问。你原始定义中的 imsi、network 等字段均为小写开头,属于未导出字段,因此 json.Marshal 会忽略它们,仅生成空的 JSON 对象 {}。
✅ 正确做法如下:
- 将结构体字段首字母大写,使其导出;
- 通过 json struct tag 显式指定 JSON 键名,保持与预期的 JSON 字段命名一致(如使用下划线风格);
- (可选)为字段添加 omitempty 标签避免零值冗余输出。
修正后的类型定义示例:
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使用方式保持不变:
立即学习“go语言免费学习笔记(深入)”;
func getGatewayInfo(spans []SpanInfo) GatewayInfo {
return GatewayInfo(spans)
}
// 示例初始化
spans := []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: "active"},
}
gatewayInfo := getGatewayInfo(spans)
jsonInfo, err := json.Marshal(gatewayInfo)
if err != nil {
log.Fatal("JSON marshal error:", err)
}
log.Printf("jsonInfo: %s", jsonInfo)
// 输出示例:
// [{"imsi":"652020105829193","network":"20801","network_status":"Registered (Roaming)","signal_quality":17,"slot":2,"state":"active"},...]⚠️ 注意事项:
- 若字段为指针或嵌套结构体,同样需确保其内部字段导出;
- json:"-" 可完全忽略某字段;json:"field,omitempty" 在字段为零值时省略该键;
- 切片类型 GatewayInfo []SpanInfo 本身无需额外实现接口,json.Marshal 原生支持切片序列化;
- 日志中用 %v 打印结构体可清晰查看字段值,而 %s 仅适用于字符串——避免误用格式动词影响调试判断。
总结:Go 的 JSON 序列化不是“自动反射所有字段”,而是基于导出性 + struct tag 的显式契约。养成从设计阶段就规范字段命名与标签的习惯,是写出健壮序列化逻辑的关键前提。










