ᕕ( ᐛ )ᕗ Jimyag's Blog

Go 1.20 新特性解析:多错误、ECDH 与覆盖率工具

· 276 words · ~ 2 min read

Last modified:

Go 1.20 发布于 2023-02-01。它的特点是“很多小但实用”的变化:泛型约束更顺手,错误处理支持多错误,HTTP 和密码学 API 都补上了重要缺口。

源码侧 api/go1.20.txt 有 9165 条公开 API 增量,大量来自 FreeBSD RISC-V syscall;公开标准库目录新增 arenacrypto/ecdhruntime/coverage

主要变化

1. comparable 约束更符合直觉

Go 1.20 调整了泛型里 comparable 的规则,让更多实际可比较的类型能满足约束。这个变化让泛型 map key、set、去重函数等代码更容易表达。

1
type Set[T comparable] map[T]struct{}

comparable 的实际意义是:类型值可以用于 ==!=,也可以作为 map key。对集合、索引、去重、缓存 key 这类泛型结构,它是最基础的约束。

2. 多错误成为标准表达

errors.Join 可以把多个错误组合成一个错误,fmt.Errorf 也支持多个 %werrors.Iserrors.As 会沿着错误树查找。

1
2
3
4
err := errors.Join(closeErr, flushErr)
if errors.Is(err, fs.ErrClosed) {
    ...
}

这个能力适合批量操作、并发任务和多阶段校验,因为它能保留多个失败原因,而不是只返回第一个。调用方仍然可以用标准错误匹配 API 判断其中是否包含某类错误。

3. crypto/ecdh 标准化密钥交换

ECDH 是现代 TLS、端到端加密和密钥协商里的基础组件。crypto/ecdh 提供统一 API,覆盖 NIST 曲线和 X25519 等常见曲线。

1
2
3
curve := ecdh.X25519()
priv, _ := curve.GenerateKey(rand.Reader)
secret, _ := priv.ECDH(peerPublic)

标准库提供这层抽象后,应用不必直接拼装低层椭圆曲线细节。API 也更难误用:私钥、公钥和曲线关系都由类型表达。

4. 覆盖率可以脱离单次 go test

runtime/coveragego tool covdata 让程序运行时写出覆盖率数据。集成测试、端到端测试、启动真实服务后的测试都能被纳入覆盖率分析。覆盖率因此不再只属于包级单元测试。

这对服务类程序很有用:可以用带覆盖率插桩的二进制跑一组 HTTP/API 测试,再把多个进程或多次运行的覆盖率数据合并。go tool covdata 负责合并、转换和输出。

语言与规范

Go 1.20 调整了 comparable 约束的规则,让更多可比较类型能满足泛型约束。它还支持从切片到数组或数组指针的转换,并补充了若干 unsafe 相关能力。

切片到数组/数组指针转换的价值在于把“长度检查 + 固定长度视图”写成语言能力:

1
2
3
var b = []byte{1, 2, 3, 4}
p := (*[4]byte)(b)
a := [4]byte(b)

转换到数组指针不会复制底层数据,适合把一段切片按固定长度协议头解释。转换到数组会复制出一个数组值。两者都会检查长度,如果切片长度不足会 panic。这个能力能减少手写 if len(b) < n 后再 copy 的样板代码,但也要明确 panic 边界。

工具链与运行时

覆盖率工具链增强明显。runtime/coveragego tool covdata 让覆盖率不再局限于 go test 的单进程测试,对集成测试、服务启动后采集覆盖率更有帮助。

PGO 进入预览阶段,编译器可以利用 profile 做优化。cgo、go versiongo testgo vet 也有改进。

标准库与新增包

新增公开包:

  • crypto/ecdh:标准 ECDH 密钥交换 API。
  • runtime/coverage:运行时覆盖率数据写出。
  • arena:实验性手动 arena 分配能力,需要实验开关。

重要变化:

  • errors.Joinfmt.Errorf 多个 %w:表达多错误。
  • net/http.ResponseController:统一控制 flush、hijack、deadline 等响应能力。
  • httputil.ReverseProxy.Rewrite:比旧 Director 更安全清晰。

ResponseController 把原来分散在可选接口里的能力收拢到一个控制器上。handler 可以通过它设置读写 deadline、flush 响应、接管连接,而不用反复做类型断言判断 ResponseWriter 是否实现了某个扩展接口。

arena 的定位是把一批对象放进同一个生命周期里,最后一次性释放。它适合非常明确的短生命周期批处理,例如解析一批临时对象后整体丢弃。风险也很直接:arena 里的对象生命周期不再完全由普通 GC 模型表达,如果对象逃到 arena 外继续使用,就会出现难排查的问题。因此它是实验包,不适合作为普通业务代码的默认内存管理方式。

小版本特殊变化

Go 1.20 系列共有 14 个小版本。因为 1.20 加入多错误、ECDH 和覆盖率能力,小版本里能看到 crypto/ecdh、covdata、HTTP 和模板修复。

安全修复重点可以分成三组。第一组是 Web 输入:net/httpmime/multipartnet/textprotohtml/template,对应请求解析、表单上传、头部解析和模板转义。第二组是路径和文件:path/filepathos,对应路径清理、平台差异和文件边界。第三组是密码学:crypto/tlscrypto/ellipticcrypto/x509crypto/rsacrypto/ecdh,它们影响 TLS、证书、密钥交换和签名验证。cmd/go 安全修复说明构建工具本身也在威胁模型内。

  • go1.20.1 修复 crypto/tlsmime/multipartnet/httppath/filepath 安全问题。
  • go1.20.2 修复 crypto/elliptic 安全问题,同时修 covdata 命令、crypto/ecdhcrypto/rsacrypto/x509
  • go1.20.3 修复 go/parserhtml/templatemime/multipartnet/httpnet/textproto 安全问题。
  • go1.20.4 包含 3 个 html/template 安全修复。
  • go1.20.5 包含 cmd/go 和 runtime 的 4 个安全修复,同时修 crypto/rsanetos
  • go1.20.8 包含 html/template 安全修复,并修 crypto/tlsgo/typesnet/httppath/filepath
  • go1.20.10net/http 安全修复小版本。
  • go1.20.12 修复 go 命令、net/httppath/filepath 安全问题。
  • go1.20.14 修复 crypto/x509,是该系列最后一个小版本。

参考

#Go #Golang #Go Release Notes #Go Errors #Go PGO