msgpack 比 json 更省空间,因其采用二进制格式,省略字段名字符串及冗余符号,仅用紧凑编码表示类型和长度,体积通常为 json 的 40%–60%;但它不是压缩算法,不压缩重复内容或使用 huffman 编码。

为什么 msgpack 比 json.Marshal 更省空间?
因为 msgpack 是二进制格式,不存字段名字符串,用紧凑编码表示类型和长度;而 json 必须把 "name"、"age" 这些键名原样写进去,还带引号和逗号。同样一个 map[string]interface{},msgpack 体积通常只有 json 的 40%–60%。
但注意:msgpack 不是压缩算法,它不压缩重复内容,也不做 Huffman 编码——只是更聪明地表达结构。想进一步减小体积,得在 msgpack 外套一层 zlib 或 zstd。
用 github.com/vmihailenco/msgpack/v5 编码 struct 最简路径
别碰老版本 v2 或没维护的 fork,v5 是当前稳定主力。它支持 struct tag(比如 msgpack:"name"),也兼容 json: tag,但优先读 msgpack:。
常见错误:忘记导出字段,或字段没加 tag 却期望控制序列化行为。
-
struct字段必须首字母大写(即导出),否则msgpack看不见 - 如果字段想跳过编码,加
msgpack:"-";想重命名,写msgpack:"user_id" - 嵌套 struct 默认递归编码,无需额外配置
- 空 slice 和 nil slice 序列化结果不同:
[]int{}编成空数组,nil编成nil值——这点和json一致
示例:
type User struct {
ID int `msgpack:"id"`
Name string `msgpack:"name"`
Tags []string `msgpack:"tags"`
}
data, _ := msgpack.Marshal(&User{ID: 123, Name: "alice", Tags: []string{"go", "msgpack"}})
msgpack.Unmarshal 失败但没报错?检查这三件事
最常踩的坑是:解码后字段全是零值,err == nil,以为成功了——其实是目标变量没传指针,或字段不可寻址。
- 必须传 **指针** 给
msgpack.Unmarshal,否则解码结果无法写入原变量 - 目标 struct 字段名必须匹配(或通过 tag 映射),且可导出;否则静默忽略
- 如果源数据字段多于目标 struct,
v5默认忽略多余字段(不像json会报错),容易误判为“兼容”
调试建议:先用 msgpack.Inspect 看原始数据结构,确认字段名和类型是否对得上。
跨语言通信时,msgpack 的整数类型怎么对齐?
Go 的 int 是平台相关(32 或 64 位),但 msgpack 协议里整数分 int8/int16/int32/int64 等明确类型。默认情况下,vmihailenco/msgpack 会根据数值大小自动选最小能容纳的类型——这点和 Python 的 msgpack 库一致,但和某些 C++ 实现可能不一致。
如果你对接的是强类型语言(如 Rust、Java),建议显式用定宽类型:
- 用
int32代替int,避免 32 位机器上int被编成int32、64 位机器上被编成int64 - 时间戳统一用
int64存 Unix 时间,别用time.Time——除非双方都启用msgpack.WithUseTime扩展 - 布尔值没问题,
bool在所有实现里都对应 msgpack 的true/false原语
真正麻烦的是浮点数精度:Go 的 float64 写入后,Python 读出来可能显示 1.2000000000000002,这不是 bug,是 IEEE 754 表达限制——别指望跨语言 float 完全相等。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











