easyjson必须手动执行easyjson -all命令生成代码,仅加//easyjson:json注释无效;需导入github.com/mailru/easyjson/json,调用u.marshaljson()或easyjson.marshal(u),禁用标准库json包。

easyjson 生成代码必须手动触发,不运行就等于没用
加了 //easyjson:json 注释不代表自动生效——它只是个标记,真正干活的是 easyjson -all xxx.go 命令。漏掉这步,调用 user.MarshalJSON() 会 panic 或 fallback 到标准库反射逻辑,性能毫无提升,还可能因字段 tag 不一致导致序列化结果错乱。
常见错误现象:undefined: User.MarshalJSON(没生成)、或返回 JSON 字段名全小写(生成后没重新编译生成文件)。
- 生成命令必须在结构体所在目录执行,生成的
xxx_easyjson.go文件要和源码一起go build - 结构体修改后(增删字段、改 tag),必须重新运行
easyjson -all,否则生成代码与结构体不匹配 - 如果用
go generate,确保//go:generate easyjson -all user.go写在结构体上方且独占一行
别直接替换 json.Marshal,调用方式变了
easyjson 不是 drop-in 替换,它把序列化逻辑“写死”在结构体方法里,所以不能继续用 json.Marshal(&u)。你得显式调用生成的方法,比如 u.MarshalJSON() 或 easyjson.Marshal(u)(后者内部仍调用前者)。
反序列化同理:easyjson.Unmarshal(data, &u) 或 u.UnmarshalJSON(data),而不是 json.Unmarshal。
- 使用
easyjson.Marshal时,传入值必须是指针或值类型,不能是interface{},否则仍走反射 fallback - 生成代码依赖
github.com/mailru/easyjson/json,项目里必须 import,否则MarshalJSON方法不可见 - 若结构体含
map[any]any或interface{}字段,easyjson 会自动降级为标准库反射处理,这部分性能不提升
time.Time 字段不能靠 tag 解决,得封装类型
写 json:"created_at,string" 对 time.Time 字段完全无效——这个 string tag 只作用于数字和布尔类型。强行加只会让序列化输出仍是 RFC3339 格式,而前端可能报错。
正确做法是定义自定义类型并实现 MarshalJSON 和 UnmarshalJSON:
type ISODate time.Time
func (t ISODate) MarshalJSON() ([]byte, error) {
return []byte(`"` + time.Time(t).Format("2006-01-02") + `"`), nil
}
func (t *ISODate) UnmarshalJSON(data []byte) error {
s := strings.Trim(string(data), `"`)
parsed, err := time.Parse("2006-01-02", s)
if err != nil {
return err
}
*t = ISODate(parsed)
return nil
}
- 别用指针接收者实现
MarshalJSON,easyjson 生成代码不识别,仍 fallback - 如果时间格式固定且高频,建议全局统一用自定义类型,避免每个 struct 单独处理
- 注意
UnmarshalJSON必须能处理空字符串、null 等边界情况,否则反序列化失败
流式写入别先 Marshal 再 Write,Encoder 才是正解
HTTP handler 里写 JSON 响应时,常见错误是:data, _ := json.Marshal(resp); w.Write(data)。这多一次内存分配,大响应体还会触发 GC;而 json.NewEncoder(w).Encode(resp) 是边序列化边写,零中间 buffer。
easyjson 同样支持流式:用 easyjson.NewEncoder(w).Encode(u),它底层复用预分配 buffer,比标准库更轻量。
- 确保
w是http.ResponseWriter且未写 header,否则Encode会 panic - 若需 SSE 或长 JSON 流,配合
http.Flusher调用Flush(),让客户端实时收到片段 - 不要在循环里反复 new Encoder,复用一个实例或用
sync.Pool管理,避免频繁初始化开销
interface{} 或深度嵌套泛型,它就退化回反射路径——这时候不如提前 flatten 结构,或换用 gjson 提取关键字段。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











