优先选 sha512.sum512:固定64字节、零分配、线程安全;流式计算用 sha512.new() 返回的 hash.hash;转字节切片用 sum[:] 而非 sum(nil),避免额外拷贝;严禁并发写入同一实例。

sha512.Sum512 和 []byte 之间怎么选
直接用 sha512.Sum512 类型比手动管理 []byte 更安全——它自带固定长度(64 字节),不会因误操作被截断或扩容,也避免了切片底层数组意外复用导致的摘要污染。但它的值语义意味着不能直接传指针修改,常见错误是写成 &sum 后反复调用 Write,结果只更新了临时副本。
- 需要多次追加数据(如流式计算):用
sha512.New()返回的hash.Hash接口,最后调用Sum(nil) - 一次性计算小数据:用
sha512.Sum512的Sum512(data)方法,零分配且线程安全 - 必须转成字节切片时:用
sum[:](注意冒号,不是.Sum(nil)),前者是固定长度视图,后者会额外拷贝并附加空字节
为什么 crypto/sha512 不接受字符串直接计算
Go 的哈希接口只认 []byte,因为字符串底层是只读字节数组,而 hash.Hash.Write 需要可变缓冲区。强行用 []byte("hello") 看似可行,但每次转换都会分配新底层数组——对高频调用(如日志签名)有明显 GC 压力。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 若输入是稳定字符串(如配置密钥):提前转成
[]byte并复用 - 若来自用户输入或网络:直接从
io.Reader流式写入sha512.New()实例,跳过中间字节转换 - 切忌用
unsafe.String强转——crypto/sha512内部不保证读取边界,可能触发 panic 或读越界
Sum512() 和 Sum(nil) 的输出长度差异
sha512.Sum512 的 Sum512() 方法返回固定 64 字节;而 hash.Hash.Sum(nil) 返回的是「当前摘要 + 你传入的切片内容」,长度 = 64 + len(nil),也就是 64。但若你传了非 nil 切片(比如 buf := make([]byte, 0, 32)),结果就是 append(buf, digest...),长度变成 32+64=96——这常被误认为“摘要变长了”。
- 要纯摘要:一律用
sum[:]或hash.Sum(nil)[:64] - 要拼接前缀(如
"sha512:" + hex.EncodeToString(sum[:])):先取sum[:]再处理,别依赖Sum的拼接行为 - Hex 编码时用
fmt.Sprintf("%x", sum[:]),别用%x直接格式化sum变量——它会打印结构体字段而非摘要值
并发写入 sha512 实例是否安全
所有 crypto/sha512 返回的哈希实例(包括 sha512.New() 和 sha512.New384())都**不支持并发写入**。内部状态(如 digest 数组、计数器)没有锁保护,多 goroutine 同时调用 Write 会导致摘要错乱,且几乎不报错——你只会得到不可重现的错误哈希值。
- 高并发场景下,每个 goroutine 必须持有独立的
sha512.Hash实例 - 不要试图复用
hash.Reset()来“节省对象”——重置后仍需重新初始化状态,不如新建更清晰 - 若必须共享(如全局计数器),用
sync.Pool管理实例,但注意 Pool 中的对象可能被任意 goroutine 获取,仍需确保单次使用独占
sha512.New384() 返回的其实是 384 位摘要(48 字节),但它底层用的仍是 SHA-512 算法,只是截断输出——和 sha512.New() 计算同一输入时,前 48 字节相同,后 16 字节不同。别指望它和标准 SHA-512 兼容。










