json.Marshal返回空字符串或错误主因是结构体字段未导出(首字母小写),需大写字段名并用json:"key,omitempty"标签;null处理需用*string等指针或sql.NullString;json.RawMessage用于延迟解析;自定义time.Time类型实现MarshalJSON/UnmarshalJSON以支持ISO8601格式。
json.Marshal 会返回空字符串或错误?常见原因是结构体字段未导出(首字母小写),json 包无法访问私有字段,序列化结果为 {} 或跳过该字段。
Name 而非 name)json:"user_name,omitempty"
omitempty 表示值为零值(""、0、
false、nil)时忽略该字段Go 的 json.Unmarshal 对 null 的处理取决于目标类型的可空性。原生类型(如 string、int)无法表示 null,反序列化时若遇到 null 会报错 json: cannot unmarshal null into Go value。
*string、*int —— null 会被转为 nil
sql.NullString 等标准空值包装器(需实现 UnmarshalJSON)UnmarshalJSON([]byte) error 方法,统一处理 null / 空字符串 / 缺失null 会解为 nil;对 slice,同理json.RawMessage 适合什么场景?当你需要延迟解析某段 JSON(比如字段结构不确定、或想避免重复解析)、或透传未知结构(如 webhook payload 中的 data 字段),json.RawMessage 是最轻量的选择 —— 它只是字节切片的别名,不触发解析开销。
json.RawMessage,反序列化时原样拷贝原始 JSON 字节json.Unmarshal 解析它,支持多次解析不同结构json.RawMessage 值,它是 []byte,需转 string 才可读null,建议用 *json.RawMessage,否则 null 会导致解析失败type Event struct {
ID int `json:"id"`
Type string `json:"type"`
Data json.RawMessage `json:"data"`
}
var e Event
json.Unmarshal([]byte(`{"id":1,"type":"user","data":{"name":"alice"}}`), &e)
// 此时 e.Data == []byte(`{"name":"alice"}`)
var user struct{ Name string }
json.Unmarshal(e.Data, &user) // 按需解析
Go 默认将 time.Time 序列化为 Go 内部格式(类似 "2006-01-02T15:04:05.999999999Z07:00"),但多数 API 要求 ISO8601(如 "2025-05-20T08:30:00Z")。直接用 time.Time 无法控制格式。
MarshalJSON 和 UnmarshalJSON
MarshalJSON 中调用 t.Format(time.RFC3339)
UnmarshalJSON 中用 time.Parse(time.RFC3339, s),注意处理带毫秒和不带毫秒的变体time.Time 和自定义时间类型,容易漏处理字段级控制比全局设置更可靠,因为不同接口对时间精度要求可能不同。