![Go 中将固定长度数组 [N]byte 转换为切片 []byte 的标准方法](https://img.php.cn/upload/article/001/246/273/177011936554789.jpg)
在 go 中,`md5.sum` 返回的是 `[16]byte` 类型(固定长度数组),而 `conn.write()` 等 i/o 函数要求 `[]byte`(切片)。二者类型不兼容,不能直接转换,但可通过切片语法 `arr[:]` 零拷贝地生成对应切片。
Go 的类型系统严格区分数组(如 [16]byte)与切片([]byte):前者是值类型、固定长度、占用栈空间;后者是引用类型、动态长度、包含底层数组指针、长度和容量。虽然 [16]byte 的底层数据布局与 []byte 兼容,但 Go 不允许隐式转换,也不支持 C 风格的强制类型转换(如 (*[]byte)(unsafe.Pointer(&arr))),因其破坏类型安全。
✅ 推荐方式:使用切片操作 sum[:]
这是最安全、高效且符合 Go 语言惯用法的方式。它不复制底层数据,仅构造一个指向原数组首地址、长度和容量均为 16 的切片:
sum := md5.Sum(data) hashSlice := sum[:] // 类型自动推导为 []byte,长度=16,容量=16 _, err := conn.Write(hashSlice) // ✅ 可直接传入 net.Conn.Write
⚠️ 注意事项:
- sum[:] 是零开销操作,适用于高频调用场景(如网络服务中批量计算哈希);
- 若需复用或延长生命周期,请确保原数组(如 sum 变量)不被提前回收——在闭包或 channel 传递时,sum[:] 会隐式持有对 sum 的引用;
- 不要误写为 sum[0:](虽等效)或 sum[:len(sum)](冗余),简洁的 sum[:] 是社区标准写法;
- 切勿使用 unsafe 手动转换,除非在极端性能敏感且经充分验证的底层库中,否则极易引发内存错误或违反 GC 假设。
? 补充:若后续需将 []byte 转回 [16]byte(例如反序列化),则必须显式拷贝(因切片长度可能不匹配):
var arr [16]byte copy(arr[:], hashSlice) // 安全拷贝前16字节
总结:面对 [N]byte ↔ []byte 转换,始终优先使用 arr[:] —— 它是 Go 内置的、类型安全、无性能损耗的标准解法。










