[翻译]Go 1.27 Release Notes

[翻译]Go 1.27 Release Notes
文章目录

Go 1.27 简介

最新的 Go 发行版 1.27 于 2026 年 8 月 发布,距 Go 1.26 六个月。本次更新主要集中在工具链、运行时和标准库的实现上。一如既往,本版本继续遵守 Go 1 的兼容性承诺。我们预期几乎所有现有的 Go 程序都能继续编译并运行。

语言变更

Go 1.27 现已支持泛型方法:方法声明可以声明自己的类型参数。这一广受期待的变化使得泛型函数可以放在某个具体数据类型的命名空间中,而不再必须把这类函数声明在整个包的作用域里。例如,math/rand/v2 现在也声明了签名为 (*Rand) N[Int intType](Int) Int 的泛型方法;此前它只有一个泛型函数 N[Int intType](Int) Int(详见下文 math/rand/v2 一节)。需要注意的是,接口方法不能声明类型参数,接口方法也不能由泛型方法来实现。

结构体字面量中的键现在可以是该结构体类型的任意合法字段选择器,而不再仅限于结构体的(顶层)字段名。

译者注:这意味着嵌入结构体中的字段可以直接作为字面量的键。官方博客中的示例如下:

type Habitat struct {
Burrow string
}

type Gopher struct {
Name string
Habitat // 嵌入结构体
}

// Go 1.27 允许直接使用 Burrow 作为键
g := Gopher{
Name: "Gopher",
Burrow: "Burrow #42",
}

函数类型推断已推广:只要把泛型函数赋值给(或转换到)匹配的函数类型,都可以进行推断。

译者注:官方博客中的示例如下。泛型函数现在可以在复合字面量、类型转换和 channel 发送中省略显式类型实参:

func GenericFormatter[T any](v T) string {
return fmt.Sprintf("value: %v", v)
}

type IntFormatter func(int) string

formatters := []IntFormatter{GenericFormatter}
fn := IntFormatter(GenericFormatter)
ch := make(chan IntFormatter, 1)
ch <- GenericFormatter

工具

compile、link、asm、cgo、cover 和 pack 工具现在支持响应文件(@file)解析。响应文件中的参数以空白分隔,支持单引号字符串、双引号字符串、转义序列,以及反斜杠加换行的续行。该格式与 GCC 的响应文件实现兼容,以便与现有构建系统互操作。

Go 命令

go 命令不再支持 bzr 版本控制系统,也无法再直接获取托管在 bzr 服务器上的模块。

GODEBUG

从 Go 1.27 开始,如果某个已被移除支持的 GODEBUG 设置(例如 asynctimerchan,见下文)出现在 go.mod 文件(godebug 条目)或 .go 源文件(//go:debug 注释)中,go 命令现在能够识别它们。若这些设置被设为移除前确立的最终默认值,则会被接受;若被设为旧值,go 命令将失败。这一变更符合 Go 1 兼容性保证 的精神:即使相应设置的支持已被移除,现有程序只要设置的是仍被接受的 GODEBUG 值,就可以继续构建和运行,无需修改。

go test

go test 现在默认会运行 stdversion vet 检查。它会报告引用文件中使用了对于当前生效的 Go 版本来说过新的标准库符号;该版本由 go.mod 中的 go 指令以及文件上的 build tag 决定。

go test -json 现在会为 "Action":"output" 行标注一个可选的新字段 "OutputType",用于说明输出类型。目前可能的取值包括 “error”、“error-continue” 和 “frame”。详见 cmd/test2json help。

go doc

go doc 命令现在支持 package@version 语法,例如 go doc example.com/pkg@v1.2.3。

go doc 命令现在接受 -ex 命令行选项,用于列出给定包或符号的可执行示例。当命令行传入示例名称(例如 go doc bytes.ExampleBuffer)时,go doc 现在会连同注释一起打印示例源码。

go fix

go fix 命令新增了若干 modernizer(atomictypes、embedlit、slicesbackward 和 unsafefuncs)。

出于风格方面的考虑,现有的 fmtappendf 分析器已被移除。

现有的 waitgroup 分析器已重命名为 waitgroupgo,以避免歧义。

go mod tidy

对于在 go.mod 中指定 go 1.27 或更高版本的模块,go mod tidy 现在会自动合并重复的 require 块。这能确保文件保持干净、标准的结构:最多两个 require 块,一个用于直接依赖,一个用于间接依赖。

合并过程中会保留依附于依赖项的现有注释块。如果某个注释块同时关联了直接依赖和间接依赖,该注释块会被合并并挂到新的直接依赖块上。

此前,如果 go.mod 积累了多个互不相连的 require 块(通常来自手工编辑、未解决的 Git 合并冲突或遗留升级),go mod tidy 会原样保留这些多余块,甚至无意中再创建新块。现在该工具会严格强制两块布局,将分散的依赖归并到各自对应的块中,并自动清理模块文件结构。

Trace

当 go tool trace 的 -http 命令行选项只传入端口(例如 -http=:6060)时,现在会把监听地址限制为 localhost。这一变更使 go tool trace 与 go tool pprof 的 -http 标志行为保持一致。若要监听所有地址,需要显式指定地址(例如 -http=0.0.0.0:6060)。

运行时

对于 go 指令配置为 Go 1.27 或更高版本的模块,traceback 现在会在标题行中包含 runtime/pprof 的 goroutine label。可通过 tracebacklabels=0 这一 GODEBUG 设置(添加于 Go 1.26)关闭该行为。该退出开关预计会长期保留,以防 goroutine label 日后包含不应出现在 traceback 中的敏感信息。

asynctimerchan GODEBUG 设置(添加于 Go 1.23)已被永久移除。time 包创建的 channel 现在始终是无缓冲(同步)的,与 GODEBUG 设置无关。

更快的内存分配

编译器现在会生成调用按尺寸特化的内存分配例程,使部分小型(小于 80 字节)内存分配的开销最多降低 30%。具体收益因负载而异,但在真实的高分配程序中,整体提升预计约为 1%。这会使二进制体积增加约 60 KB(与负载无关)。如果发现任何回归,请提交 issue。可以在构建时设置 GOEXPERIMENT=nosizespecializedmalloc 来关闭该优化。该退出设置预计会在 Go 1.28 中移除。

Goroutine 泄漏 profile

一种报告泄漏 goroutine 的新 profile 类型此前在 Go 1.26 中作为实验提供,现在已正式可用。该 profile 类型名为 goroutineleak,由 runtime/pprof 包支持,也可通过 net/http/pprof 端点 /debug/pprof/goroutineleak 获取。

所谓泄漏的 goroutine,是指阻塞在某个并发原语(channel、sync.Mutex、sync.Cond 等)上、且该原语不可能再被解除阻塞的 goroutine。运行时借助垃圾回收器检测泄漏:如果 goroutine G 阻塞在并发原语 P 上,而 P 从任何可运行的 goroutine、以及这些 goroutine 可能解除阻塞的其他 goroutine 都不可达,那么 P 无法被解除阻塞,G 也就永远无法被唤醒。虽然无法在所有情况下都检测出永久阻塞的 goroutine,但这种方法能覆盖很大一类泄漏。

由于该技术建立在可达性之上,如果泄漏是由阻塞在全局变量、或可运行 goroutine 局部变量所引用的并发原语上引起的,运行时可能无法识别。

示例见 Go 1.26 发行说明。

特别感谢 Uber 的 Vlad Saioc 贡献了这项工作。

goroutineleakprofile GOEXPERIMENT 设置现已删除。

编译器

编译器现在会把 //line 或 /*line*/ 指令中的相对文件名解析为相对于包含该指令的文件所在目录,这与 go/scanner 的行为一致。绝对文件名不受影响。参见 #70478。

编译器现在会为函数字面量(闭包)生成更简单的名字。此前,当包含该字面量的函数被内联时,函数字面量的名字可能变得很长。现在无论是否内联,编译器都会为该函数字面量选择相同的名字。它还可能把同一函数字面量的多个实例(因其包含函数被内联而产生)合并,在编译后的二进制中共享同一段代码。这一变更不影响 Go 代码的功能。检查符号名的测试可能需要更新,不过建议不要依赖函数字面量的名字。对于错误地比较函数代码指针是否相等的程序,该问题在 Go 1.27 中可能更容易暴露:捕获了不同闭包数据的函数字面量,在更多情况下可能具有相同的代码指针。

链接器

在面向 macOS 时,链接器现在接受 -macos 和 -macsdk 命令行选项,用于在 LC_BUILD_VERSION load command 中指定 OS 和 SDK 版本。默认情况下,它会选择当前仍受支持的最老 macOS 版本(目前为 13.0.0)以及较新的 SDK 版本(目前为 26.2.0)。

标准库

新增 encoding/json/v2 与 encoding/json/jsontext 包

现在提供了两个新包:

v2 包采用比 v1 更严格、也更利于互操作的默认行为:它会拒绝 JSON 字符串中的非法 UTF-8,并拒绝 JSON 对象中的重复名称。完整的行为差异以及可用于调整这些行为的选项,见 v1 encoding/json 包文档。

encoding/json 包现在由 v2 实现驱动。编解码行为得以保留,但错误信息的具体文本可能不同。该包还新增了一批 Options,可以把 v2 配置成按 v1 语义工作,从而不必一次性迁移到新 API。v1 API 将继续受支持,用户不必迁移。

Marshal 性能与此前实现大体持平,Unmarshal 性能则显著更快。

如果遇到与新实现的兼容性问题,可以在构建时设置 GOEXPERIMENT=nojsonv2 来关闭它,从而恢复原来的 v1 实现。该退出开关预计会在未来版本中移除。

背景和更多细节见提案 issue。如果需要关闭新实现,请提交 issue。

新增 crypto/mldsa 包

新的 crypto/mldsa 包实现了 FIPS 204 中规定的后量子 ML-DSA 签名方案。

crypto/x509 现在支持 ML-DSA 私钥、公钥和签名。

crypto/tls 现在在 TLS 1.3 中支持 ML-DSA 签名,并新增 MLDSA44、MLDSA65 和 MLDSA87 这几个 SignatureScheme 值。

新增 uuid 包

新的 uuid 包用于生成和解析 UUID。

新增实验性 simd 包

Go 1.27 引入了新的实验性 simd 包,提供可移植、且与向量宽度无关的 SIMD 支持。在硬件指令可用时会使用硬件指令。该包通过在构建时设置环境变量 GOEXPERIMENT=simd 启用。

simd 包在所有架构上都可用,并提供尺寸未指定的向量类型,例如 Int8s 和 Float32s。它支持 simd/archsimd 包中那些跨架构、跨向量宽度有硬件支持或易于模拟的“可伸缩”操作子集。

更多细节见提案 issue。

实验性 simd/archsimd 包

Go 1.27 继续为始于 Go 1.26 的 simd/archsimd 包提供实验性 SIMD 操作支持。本版本修订了 amd64 API,并新增了对 arm64 “Neon” 128 位 SIMD 以及 WebAssembly 128 位 SIMD 的支持。simd/archsimd 包同样通过构建时设置环境变量 GOEXPERIMENT=simd 启用。

该包提供架构相关的 SIMD 操作。它在 wasm、arm64 和 amd64 上支持 128 位向量类型,并在部分 amd64 处理器上支持 256 位和 512 位向量类型。API 尚未视为稳定。

更多细节见包文档和提案 issue。

我们计划在未来版本中为更多架构提供支持,但该 API 有意做成架构相关,因此不可移植。

标准库的其余变更

bytes

新增 CutLast 函数,按分隔符最后一次出现的位置切分 []byte。它可以替代并简化一些常见的 LastIndex 用法。

compress/flate

Go 1.27 提升了压缩速度。由于编码器实现变更,Writer 产出的精确编码结果可能与 Go 1.26 不同。因为 DEFLATE 是 archive/zip、compress/gzip、compress/zlib 和 image/png 所使用的底层压缩,这些包的输出也可能发生变化。

crypto

新增 MLDSAMu 这一 Hash 值,用作 External μ ML-DSA 签名的信号机制。

crypto/ecdsa

如果提供了非 nil 的 SignerOpts,PrivateKey.Sign 现在会检查 hash 长度是否正确。

crypto/tls

新增 QUICConfig.ClientHelloInfoConn 字段,用于指定 QUIC 服务端握手期间 ClientHelloInfo.Conn 所使用的 net.Conn。

现在支持 MLKEM1024 密钥交换。可以通过将其加入 Config.CurvePreferences 来启用。

Config.Rand 现已弃用。若需要确定性测试,请使用 testing/cryptotest.SetGlobalRandom。

即使使用了 tlsmlkem=0 或 tlssecpmlkem=0 这些 GODEBUG 选项,现在也可以在 Config.CurvePreferences 中显式启用后量子混合密钥交换。这些选项原本就只应作用于 Config.CurvePreferences 为 nil 时的默认集合。

新增 ConnectionState.LocalCertificate 字段,包含握手期间呈现给对端的证书链。

以下 GODEBUG 设置已被永久移除:tlsunsafeekm(添加于 Go 1.22)、tlsrsakex(添加于 Go 1.22)、tls3des(添加于 Go 1.23)、tls10server(添加于 Go 1.22)以及 x509keypairleaf(添加于 Go 1.23)。

crypto/x509

解析到 pkix.Name 字段时,现在支持更广泛的 pkix.AttributeTypeAndValue.Value 类型;未知类型会被解析为 asn1.RawValue。

新增 Certificate.RawSignatureAlgorithm、CertificateRequest.RawSignatureAlgorithm 和 RevocationList.RawSignatureAlgorithm 字段,用于暴露签名算法的 DER 编码 AlgorithmIdentifier,即使 SignatureAlgorithm 字段为 UnknownSignatureAlgorithm 时也是如此。

SystemCertPool 现在在 Windows 和 Darwin 上也会尊重 SSL_CERT_FILE 和 SSL_CERT_DIR。设置这些环境变量后,会从磁盘加载根证书,并改用 Go 原生验证器,而不再使用平台证书验证 API。该行为可通过 GODEBUG=x509sslcertoverrideplatform=0 关闭。

crypto/x509/pkix

RDNSequence.String(因此也包括 Name.String)现在即使属性的 OID 无法识别,也会把字符串类型的属性值渲染为字符串。此前这类值总会以其 DER 形式做十六进制编码。参见 #33093。

database/sql

新增 ConvertAssign 函数,让数据库驱动可以访问 Rows.Scan 所执行的类型转换。

database/sql/driver

驱动可以实现新的 RowsColumnScanner 接口,直接扫描到用户提供的目标值。

go/constant

新增 StringLen 函数,可在不完全构造字符串 Value 的情况下返回其长度。

go/scanner

扫描器现在可以通过新的 Scanner.End 方法获取 token 的结束位置。

go/token

File 现在有了 String 方法。

go/types

Hasher 类型是面向 Type 的 maphash.Hasher 实现,并遵守 Identical 等价关系,从而允许把 Type 用在哈希表及类似数据结构中。HasherIgnoreTags 则是对应 IdenticalIgnoreTags 的 hasher。

gotypesalias GODEBUG 设置(添加于 Go 1.22)已被永久移除;go/types 包现在无论 GODEBUG 如何设置,都会为别名声明生成 Alias 类型节点。

hash/maphash

Hasher 接口定义了某一类型的值与未来基于哈希的数据结构(例如哈希表和布隆过滤器)之间的约定;参见 #70471。

ComparableHasher 类型为可比较类型提供了便捷的 Hasher 实现,其 Equal 方法定义为 ==。

math/big

Int 现在有了 Divide 方法,用于计算两个 Int 值的商和余数。它支持舍入模式 Trunc、Floor、Round 和 Ceil。

math/rand/v2

Rand 现在支持泛型方法 N,行为与包级 N 函数一致。

net

UnixConn 的读方法在底层读取返回 EOF 时,现在会直接返回 io.EOF,而不再把它包装进 net.OpError。

net/http

Transport 和 Server 现在支持在用户提供的、实现了 ConnectionState() tls.ConnectionState 方法的 net.Conn 连接上进行 TLS ALPN 协议协商。

HTTP/2 服务端现在会接受 RFC 9218 定义的客户端优先级信号,从而优先处理更高优先级的 HTTP/2 stream。如果希望沿用旧行为(无论优先级如何都以 round-robin 方式处理 stream),可将 Server.DisableClientPriority 设为 true。

HTTP/1 的 Response.Body 在关闭时现在会自动排空尚未读取的内容(有一个保守上限),以便更好地复用连接。对大多数程序来说,这一变更应是无操作,或会带来性能提升。在少数情况下,如果程序并不能从连接复用中获益,却错误地让过多空闲连接一直挂着——通常是把 Transport.MaxIdleConns 设为 0,或对不同请求使用不同的 Client,从而绕过 Transport.MaxIdleConns 限制——则可能出现性能下降。此时可将 Transport.DisableKeepAlives 设为 true 来关闭连接复用。不过,这类性能下降通常说明 Transport 或 Client 的配置或用法本身就不合理,更深入地检查一下往往会更有帮助。

新增 Server.MaxHeaderValueCount 字段,允许 HTTP 服务端控制愿意接受的 header 值数量。未设置时使用 DefaultMaxHeaderValueCount。

net/http/httptest

新增 NewTestServer 函数,用于创建配置了内存假网络的 Server,适合与 testing/synctest 包一起使用。

net/url

新增 URL.Clone 方法,用于深拷贝 URL。新增 Values.Clone 方法,用于深拷贝 Values。

runtime/secret

在机密模式下创建的 goroutine,现在会同样在机密模式下执行。

strings

新增 CutLast 函数,按分隔符最后一次出现的位置切分字符串。它可以替代并简化一些常见的 LastIndex 用法。

syscall

在 Plan 9 上,Errno 类型现已定义,并像其他平台一样实现了 error 接口。Plan 9 的系统调用返回的是 ErrorString 值,因此该包在 Plan 9 上永远不会返回 Errno。定义它是为了让引用 syscall.Errno 的可移植代码无需 build constraint 即可在 Plan 9 上构建。

testing/synctest

新增 Sleep 辅助函数,组合了 time.Sleep 和 synctest.Wait。

unicode

unicode 包以及系统中相关支持已从 Unicode 15 升级到 Unicode 17。变更说明见 Unicode 16.0.0 和 Unicode 17.0.0 发行说明。

移植

Darwin

正如 Go 1.26 发行说明中所宣布的,Go 1.27 要求 macOS 13 Ventura 或更高版本;对更早版本的支持已经停止。

PowerPC

在 Linux 上的大端 64 位 PowerPC 移植(GOOS=linux GOARCH=ppc64)中,Go 工具链现在会生成使用 ELFv2 系统 ABI 的二进制。ELFv2 支持需要 Linux kernel 3.13 或更高版本。RHEL7 已将该支持回移植到其 3.10 内核。

现在支持 cgo、位置无关可执行文件(PIE)以及外部链接。使用这些特性需要兼容 ELFv2 的运行时(libc 以及所有被链接和加载的库)。

对于不使用 cgo 的程序,Go 工具链默认仍会用内部链接生成静态二进制。对于带有 cgo 选项的程序,如果需要静态的纯 Go 二进制,可以在运行 go build 时设置环境变量 CGO_ENABLED=0。

最后更新: