md5.sum() 已弃用,新代码必须用 md5.new() + write() + sum(nil) 组合,否则 go 1.22+ 编译会触发 deprecation 警告,且语义不一致。

md5.Sum() 已弃用,新代码必须用 md5.New() + Write() + Sum(nil) 组合,否则 Go 1.22+ 编译会触发 deprecation 警告,且语义不一致。
md5.Sum() 为什么不能直接用
很多人写 md5.Sum([]byte("hello")) 后直接传给 hex.EncodeToString(),结果 panic 或输出异常——因为 md5.Sum() 返回的是 md5.Sum 类型(底层是结构体,含一个 [16]byte 字段),不是 []byte。你得显式取 sum[:] 才能拿到切片视图。
更关键的是:Go 1.22 起该函数被标记为 deprecated,文档明确建议迁移到流式路径。它也不支持增量写入,每次调用都是独立计算,无法复用 hasher 状态。
-
md5.Sum(data)是“一次性快照”,不兼容后续 Write - 返回值类型是
md5.Sum,不是[]byte,直接 fmt.Printf("%x", sum) 依赖 fmt 对结构体的隐式处理,可读性差、易出错 - 若你正在写库或长期维护项目,现在就该删掉所有
md5.Sum()调用
字符串 MD5 的标准写法(推荐)
对纯字符串做哈希,最简洁安全的方式是:
h := md5.New()
h.Write([]byte("hello world"))
sum := h.Sum(nil) // 返回 []byte,长度恒为 16
result := hex.EncodeToString(sum)
注意三点:
-
Sum(nil)的参数必须是nil,表示新建底层数组;传非 nil 切片会追加,容易导致长度 > 16 - 别在
Sum()后继续Write()—— Go hash 实现不保证 reset 行为,应重新md5.New() - 中文或含 UTF-8 的字符串无需额外处理,
[]byte(text)已正确编码,但确保输入一致(比如不要混用 \r\n 和 \n)
大文件或流式数据必须用 io.Copy
用 md5.Sum(os.ReadFile(path)) 处理几十 MB 的文件,会直接 OOM。MD5 设计就是流式接口,hash.Hash 实现了 Write(),天然适配 io.Copy。
正确做法:
f, _ := os.Open("big.zip")
defer f.Close()
h := md5.New()
io.Copy(h, f) // 自动分块、零拷贝、内存可控
sum := h.Sum(nil)
- 别自己写
bufio.NewReader+ 循环Read——io.Copy更简、更稳、更少 bug - 如果需同时校验和保存文件,可用
io.TeeReader(f, h),避免二次读取 - HTTP body、gzip stream、数据库 blob 等不可 seek 的 reader,也适用此模式
测试时最容易错的比较方式
单元测试里常见错误:把 []byte 和十六进制字符串直接比较。
比如这样写是错的:
got := myHash("test") // 返回 []byte
if got != []byte("098f6bcd4621d373cade4e832627b4f6") { ... } // 类型不匹配,永远 false
正确做法只有一种:
- 要么统一转成字符串:
hex.EncodeToString(got) == "098f6bcd..." - 要么统一转成字节:
hex.DecodeString("098f6bcd...")得到期望的[]byte,再用bytes.Equal() - 永远别用
fmt.Sprintf("%x", got)做断言 —— 它依赖 fmt 实现细节,不同 Go 版本可能输出空格或换行
真正容易被忽略的点是:MD5 输出是确定的 16 字节,但 Sum(nil) 返回的 []byte 是 slice,其 cap 可能大于 16;若你误用 append() 或 copy() 到非零初始化的底层数组,可能污染历史数据。始终用 Sum(nil) 获取干净结果。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











