json.Marshal返回空字符串或nil的最常见原因是结构体字段未导出(首字母小写),导致encoding/json包完全跳过这些字段,仅序列化首字母大写的导出字段;若全部字段未导出,则结果为{}。

json.Marshal 不会自动处理 nil 指针、未导出字段或循环引用——用错就 panic 或返回空数据,不是“不生效”,而是根本没进编码逻辑。
为什么 json.Marshal 返回空字符串或 nil?
最常见原因是结构体字段没导出(首字母小写),Go 的 json 包完全跳过它们:
type User struct {
name string // 小写 → 不参与 JSON 编码
Age int // 大写 → 编码为 "Age"
}
data, _ := json.Marshal(User{name: "Alice", Age: 30})
// 输出:{"Age":30},name 字段彻底消失
- 检查所有要序列化的字段是否首字母大写
- 若需保留小写字段名,加
json标签:name string `json:"name"` - 嵌套结构体同理:内部字段也必须可导出,否则整个嵌套对象变
null
json.Marshal 遇到 nil 指针时的行为
对 *string、*int 等指针类型,json.Marshal 默认把 nil 编码为 null,但如果你传的是 nil 接口或 nil 切片,会直接 panic:
var s *string
json.Marshal(s) // → "null"
var arr []int
json.Marshal(arr) // → "[]" 正常
var i interface{}
json.Marshal(i) // panic: json: unsupported type: <nil>
- 传入前务必确认非
nil接口值;可用if i != nil防御 - 切片/映射为
nil是合法的,会分别编码为[]和{} - 若想让零值字段不出现在 JSON 中,用
omitempty标签:Age int `json:"age,omitempty"`
时间类型、自定义类型怎么正确序列化?
time.Time 默认编码为 RFC3339 字符串(如 "2024-05-20T14:30:00Z"),但如果你用的是自定义时间类型(比如包装了 time.Time 的结构体),json.Marshal 会忽略其方法,只看字段——除非它实现了 MarshalJSON() 方法:
立即学习“go语言免费学习笔记(深入)”;
type MyTime time.Time
func (t MyTime) MarshalJSON() ([]byte, error) {
return []byte(`"` + time.Time(t).Format("2006-01-02") + `"`), nil
}
- 所有需要特殊序列化的类型,必须实现
MarshalJSON() ([]byte, error) - 别忘了返回带双引号的字符串字节(JSON 字符串字面量)
- 标准库类型如
url.URL、net.IP已内置MarshalJSON,可直接用
真正容易卡住的地方不在语法,而在字段导出性、接口值判空、以及自定义类型的序列化契约——漏掉任意一环,json.Marshal 就不会按你想的那样工作。


















