sonic.Unmarshal 对 nil 指针 panic 是设计选择,强制暴露空值误用;time.Time 默认序列化为纳秒整数,需手动注册格式;CGO 未启用会导致性能下降;GetByPath 路径错误静默返回 nil,须先 TypeSafe() 判断。

sonic.Unmarshal 为什么 panic 而不是返回 error?
因为 sonic.Unmarshal 默认对 nil *struct{}、nil []T 或未初始化的指针直接 panic,不像标准库那样输出 null 或静默跳过。这不是 bug,是设计选择——用 panic 强制暴露空值误用,避免隐式错误扩散。
常见错误现象:panic: cannot unmarshal into nil pointer 出现在你传了 &v 但 v 是未初始化的 *MyStruct。
- 实操建议:解码前显式判空,或统一用
sonic.Config{NoNullSliceOrMap: true}初始化配置 - 若必须兼容标准库行为,改用
sonic.UnmarshalString+ 手动检查字符串是否为空 - 注意:这个 panic 不会被
recover()捕获(底层是 C++ 异常转 Go panic),所以别指望 defer recover 处理它
time.Time 序列化出来是数字而不是时间字符串?
sonic.Marshal 默认把 time.Time 当作纳秒整数序列化,输出类似 1711909281000000000,而非 RFC3339 格式。这是性能取舍——跳过格式化节省 3–5μs/次,但业务上几乎总是错的。
原因在于 sonic 不自动注册任何时间格式器,而标准库内置了 RFC3339Nano。
立即学习“go语言免费学习笔记(深入)”;
- 必须手动注册:
sonic.RegisterTimeFormat("2006-01-02T15:04:05Z07:00") - 注册只需一次,在
init()或 main 开头调用即可 - 如果结构体字段带
json:"time,string"tag,还需额外加sonic.OptionNoQuoteTextMarshaler,否则会多包一层引号
CGO 环境下 Docker 构建失败或 fallback 到纯 Go 模式?
看到构建日志里有 building for purego 或运行时性能只有标准库 1.2 倍,基本就是 CGO 没生效。sonic 的高性能依赖 C++ JIT 和 SIMD,purego 分支只是保底。
典型错误场景:Alpine 镜像没装 g++ 和 musl-dev,或构建命令加了 -tags purego。
- Dockerfile 必须包含:
RUN apk add --no-cache g++ musl-dev - Go 构建命令不能含
-tags purego;如需强制指定标签,改用-tags "amd64 avx2" - 检查是否生效:
go env CGO_ENABLED必须为"1",且运行时打印sonic.Version()应含"native"字样
GetByPath 性能远超嵌套 .Get(),但路径字符串写错就静默返回 nil?
ast.Node.GetByPath 支持 "user.profile.age" 或 []interface{}{"user", "profile", "age"},内部走哈希查表,比三次 .Get("user").Get("profile").Get("age") 快 3–4 倍。但它不校验路径合法性——键不存在、类型不匹配、越界访问,一律返回 nil 节点,不会报错。
容易踩的坑:你拿到 nil 后直接调 .Int64(),触发 panic:panic: cannot convert nil node to int64。
- 务必先用
.TypeSafe()判断类型,再取值;Type()在并发下不安全 - 路径中混用字符串和数字索引要小心:
"items.0.name"合法,"items[0].name"不合法(不支持方括号语法) - 调试时可临时加
fmt.Printf("path %v => %+v\n", path, node),node为nil就说明路径断在某层



















