因为binary包比JSON更紧凑高效:JSON将12345序列化为5字节字符串,binary.Write直接写入4字节int32二进制,节省40%~60%带宽,且无反射和Unicode转义开销;但要求结构体字段导出、顺序固定、字节序显式一致,不支持schema版本管理或可选字段。
binary 包而不是 JSON 或字符串序列化?因为 Go 的 encoding/json 会把整数转成 ASCII 字符串(比如 12345 占 5 字节),而 binary.Write 能直接写入 int32 的 4 字节二进制表示,省掉解析开销和冗余字符。尤其在高频小包场景(如 IoT 设备心跳、实时行情推送),带宽节省常达 40%~60%。
但要注意:binary 包不处理字段名、类型信息或版本兼容——它只管“按你声明的顺序和类型,一字节不差地塞进去”。所以前后端必须严格约定结构体定义和字节序。
binary.Write 和 binary.Read 怎么配对使用才不出错?核心是三点:结构体字段必须导出(首字母大写)、字段顺序不能变、binary 默认用 binary.BigEndian,但你要显式传入,别依赖包级默认值。
binary.Write(w, binary.LittleEndian, &s) 和 binary.Read(r, binary.BigEndian, &s) 混用 → 解出来全是错值int(平台相关)和 int32(固定 4 字节)→ 在 32 位机器上 int 是 4 字节,64 位上是 8 字节,读写必然错位binary.Write → 会 panic,得手动序列化长度 + 元素示例:
立即学习“go语言免费学习笔记(深入)”;
type Packet struct { Timestamp int64 Code uint16 Value float32}buf := new(bytes.Buffer)err := binary.Write(buf, binary.BigEndian, Packet{16987654321, 1001, 3.14}) // ✅ 固定类型 + 显式字节序
binary 包本身不提供 schema 版本管理,得靠你在结构体里预留字段或加 header。
Flags uint8 字段,bit0 表示是否含扩展数据,bit1 表示是否含校验和常见坑:struct{ A int32; B int32 } 和 struct{ A int32; _ [4]byte; B int32 } 在内存布局上不同,即使都占 8 字节,binary.Write 也会按字段逐个写,第二个结构体会把 _ 当成真实字段写 4 个 0,导致接收方解析失败。
binary.Write 内部用了反射,对高频小结构体(比如每秒万次)有明显开销。生产环境建议:
binary.Write 做原型验证,上线前手写 WriteTo(io.Writer) 方法,直接调 WriteUint32 等函数bytes.Buffer:用 buf.Reset() 清空,避免频繁 alloc[8]byte 手动拼接,比反射快 3~5 倍(实测)另外,binary.Read 同样反射,且每次都要新建目标变量。更稳的做法是预先分配结构体指针,传给 binary.Read 的第二个参数。
二进制编码省带宽这事很实在,但代价是协议僵硬——改一个字段位置,上下游就得同步发版。很多团队卡在这儿,不是不会写 binary.Write,而是没想清楚字段生命周期怎么管。