最新的 Go 发行版 1.25 于 2025 年 8 月发布,距离 Go 1.24 已过六个月。本次版本的大部分改动集中在工具链、运行时和标准库的实现上。和以往一样,本次发布遵循 Go 1 的兼容性承诺。我们预计几乎所有的 Go 程序仍然可以像以前一样编译并运行。
Go 1.25 没有影响现有 Go 程序的语言变更。但在语言规范中移除了"核心类型"的概念,改用更具体的描述性文字,这对日常开发无实际影响,但让语言规范更清晰易懂。
go build -asan 选项现在默认在程序退出时进行泄漏检测。如果由 C 分配的内存既未被释放,又不被任何其他由 C 或 Go 分配的内存引用,则会报告错误。运行程序时可以通过在环境中设置 ASAN_OPTIONS=detect_leaks=0 来禁用这些新错误报告。
Go 发行版将包含更少的预构建工具二进制文件。像编译器和链接器这样的核心工具链二进制仍会被包含,但那些在构建或测试操作中不被调用的工具将在需要时由 go tool 构建并运行。
新的 go.mod ignore 指令可用于指定 go 命令应忽略的目录。位于这些目录及其子目录中的文件在匹配包模式(例如 all 或 ./...)时会被 go 命令忽略,但仍会包含在模块 zip 文件中。
新的 go doc -http 选项将启动一个文档服务器,展示所请求对象的文档,并在浏览器窗口中打开该文档。
新的 go version -m -json 选项会打印给定 Go 二进制文件中嵌入的 runtime/debug.BuildInfo 结构的 JSON 编码。
go 命令现在支持在解析模块路径时将仓库的子目录作为模块根路径,通过使用类似 的语法来指示 root-path 对应于 repo-url 中的 subdir 子目录(由版本控制系统 vcs 管理)。
新的 work 包模式会匹配 work(原名为 main)模块中的所有包:在 module 模式下为单个 work 模块,或在 workspace 模式下为工作区内的一组模块。
当 go 命令更新 go.mod 或 go.work 文件中的 go 行时,不再添加一行 toolchain 来指定当前命令的版本。
go vet 命令包含了新的分析器:
GOMAXPROCS 的默认行为已改变。此前版本中,GOMAXPROCS 默认为启动时可用的逻辑 CPU 数(runtime.NumCPU)。Go 1.25 引入了两项改变:
如果通过 GOMAXPROCS 环境变量或调用 runtime.GOMAXPROCS 手动设置了 GOMAXPROCS,上述两种行为会自动被禁用。也可以通过 GODEBUG 设置显式禁用,分别为 containermaxprocs=0 和 updatemaxprocs=0。
为了支持读取更新后的 cgroup 限制,运行时将在进程生命周期内为 cgroup 文件保留已缓存的文件描述符。
现在可以作为实验性功能使用一个新的垃圾回收器。该回收器通过改进局部性和 CPU 可扩展性,提升对小对象的标记与扫描性能。基准测试结果存在差异,但我们预计在大量依赖垃圾回收的实际程序中,垃圾回收开销可减少约 10% 到 40%。
可以在构建时通过设置环境变量 GOEXPERIMENT=greenteagc 来启用新的垃圾回收器。该设计预计将继续演进改进,因此我们鼓励 Go 开发者试用并反馈他们的使用体验。有关设计细节和提交反馈的说明,请参见相应的 GitHub issue。
运行时执行跟踪长期以来是理解和调试应用程序底层行为的强大但代价高昂的手段。不幸的是,由于跟踪数据体积大且持续写入开销高,这种方式通常不适用于调试罕见事件。
新的 runtime/trace.FlightRecorder API 提供了一种轻量级的方式来捕获运行时执行跟踪:它将跟踪持续记录到一个内存环形缓冲区中。当发生重要事件时,程序可以调用 FlightRecorder.WriteTo,将最近几秒的跟踪快照写入文件。通过让应用只捕获关心的跟踪片段,这种方法能够生成更小的跟踪文件。
FlightRecorder 捕获的时间长度和数据量可以在 FlightRecorderConfig 中进行配置。
当程序因一个被 recover 后又重新 panic 的未处理 panic 而退出时,打印的消息不再重复 panic 值的文本。
之前,一个先 panic("PANIC"),recover 后又用原值重新 panic 的程序会打印:
panic: PANIC [recovered]
panic: PANIC
现在该程序将打印:
panic: PANIC [recovered, repanicked]
在启用了匿名虚拟内存区域(VMA)名称支持(CONFIG_ANON_VMA_NAME)的 Linux 系统上,Go 运行时会在匿名内存映射中添加用于说明其用途的注释。例如,堆内存会被标注为 [anon: Go: heap]。可以通过将 GODEBUG 设置为 decoratemappings=0 来禁用此功能。
此版本修复了一个在 Go 1.21 中引入的编译器错误,该错误可能会错误地延迟对 nil 指针的检查。类似下面这样的程序,过去会(错误地)成功执行,现在将会(正确地)因空指针异常而 panic:
package main
import "os"
func main() {
f, err := os.Open("nonExistentFile")
name := f.Name()
if err != nil {
return
}
println(name)
}
此程序是错误的,因为在检查错误之前就使用了 os.Open 的返回值。如果 err 非 nil,那么 f 可能为 nil,此时调用 f.Name() 应该引发 panic。然而在 Go 1.21 到 1.24 中,编译器错误地将对 nil 的检查延迟到了错误检查之后,导致程序错误地成功执行,违反了 Go 规范。在 Go 1.25 中,它将不再成功运行。如果此更改影响到你的代码,解决方法是尽早进行 err != nil 的检查,最好在产生该错误的语句之后立即进行。
Go 1.25 中的编译器和链接器现在使用 DWARF 第 5 版来生成调试信息。更新的 DWARF 版本减小了 Go 可执行文件中调试信息所占的空间,并缩短了链接时间,尤其是对于大型 Go 二进制文件。可以在构建时通过设置环境变量 GOEXPERIMENT=nodwarf5 来禁用 DWARF5 的生成(此回退选项在将来的 Go 发行版中可能会被移除)。
编译器现在在更多情况下能够将切片的底层存储分配到栈上,从而提高性能。此更改可能会放大对不正确使用 unsafe.Pointer 的影响,例如参见 issue 73199。为定位这些问题,可使用 bisect 工具并加上 -compile=variablemake 标志来查找导致问题的分配。所有此类新的栈上分配也可以通过 -gcflags=all=-d=variablemakehash=n 来关闭。
链接器现在接受 -funcalign=N 命令行选项,用于指定函数入口的对齐方式。默认值依赖于平台,在本次发布中保持不变。
新的 testing/synctest 包为测试并发代码提供支持。
Test 函数在一个隔离的“泡”中运行测试函数。在该“泡”内时间被虚拟化:time 包的函数在一个伪时钟上运行;如果“泡”内的所有 goroutine 都被阻塞,时钟会立即向前推进。
Wait 函数等待当前“泡”内的所有 goroutine 都阻塞。
该包首次在 Go 1.24 中以 GOEXPERIMENT=synctest 实验形式提供,API 与现在略有不同。该实验现已毕业为正式功能。若设置了 GOEXPERIMENT=synctest,旧的 API 仍然可用,但将在 Go 1.26 中移除。
Go 1.25 包含一个新的实验性 JSON 实现,在构建时通过设置环境变量 GOEXPERIMENT=jsonv2 来启用。
启用后,会提供两个新包:
此外,当启用 “jsonv2” GOEXPERIMENT 时:
我们鼓励 encoding/json 的用户在启用 GOEXPERIMENT=jsonv2 的情况下测试他们的程序,以帮助发现新实现可能带来的兼容性问题。
我们预计 encoding/json/v2 的设计将继续演进,鼓励开发者试用新 API 并在提案问题中提供反馈。
Writer.AddFS 的实现现在支持对实现了 io/fs.ReadLinkFS 的文件系统处理符号链接。
Unmarshal 和 UnmarshalWithParams 现在对 ASN.1 类型 T61String 和 BMPString 的解析更加一致。这可能导致之前被接受的一些格式错误的编码现在被拒绝。
MessageSigner 是一个新的签名接口,供希望自行对待签名消息进行哈希的签名器实现。还引入了一个新函数 SignMessage:它会尝试将一个 Signer 接口升级为 MessageSigner;如果升级成功则使用 MessageSigner.SignMessage 方法,否则回退使用 Signer.Sign。此机制可用于同时支持 Signer 和 MessageSigner 的代码路径。
程序启动后更改 fips140 的 GODEBUG 设置现在不会生效(无操作)。此前文档中禁止更改,且更改可能导致 panic。
在 amd64 平台上,如果不可用 AVX2 指令,SHA-1、SHA-256 和 SHA-512 的速度现在会变慢。自 2015 年以来生产的所有服务器处理器(以及大多数其他处理器)都支持 AVX2。
新的 ParseRawPrivateKey、ParseUncompressedPublicKey、PrivateKey.Bytes 和 PublicKey.Bytes 函数/方法实现了低层编码,省去了使用 crypto/elliptic 或 math/big 的需要。
在启用 FIPS 140-3 模式时,签名速度现提高为原来的 4 倍,与非 FIPS 模式的性能一致。
在启用 FIPS 140-3 模式时,签名速度现在提升为原来的四倍,达到与非 FIPS 模式相同的性能。
某些 Curve 实现中隐藏且未记录的 Inverse 和 CombinedMult 方法已被移除。
PublicKey 不再声称模数(modulus)值被视为机密。VerifyPKCS1v15 和 VerifyPSS 已经警告所有输入都是公开的并可能被泄露,且存在可以从其他公开值恢复模数的数学攻击。
密钥生成现在快了三倍。
在 amd64 平台上,当可用 SHA-NI 指令时,哈希运算现在快了两倍。
新的 SHA3.Clone 方法实现了 hash.Cloner 接口。
在 Apple M 处理器上,哈希速度现在提高了两倍。
新的 ConnectionState.CurveID 字段公开了用于建立连接的密钥交换机制。
新的 Config.GetEncryptedClientHelloKeys 回调可用于在客户端发送 Encrypted Client Hello 扩展时,为服务器设置 EncryptedClientHelloKeys。
根据 RFC 9155,在 TLS 1.2 握手中已不再允许使用 SHA-1 签名算法。可通过将 GODEBUG 设置为 tlssha1=1 来重新启用它们。
在启用 FIPS 140-3 模式时,TLS 1.2 现在要求使用 Extended Master Secret,并且允许使用 Ed25519 和 X25519MLKEM768。
TLS 服务器现在偏好使用最高支持的协议版本,即使这不是客户端最优先的版本。
TLS 客户端和服务器在遵从规范并拒绝不符合规范的行为方面变得更严格。与遵循规范的对端建立的连接应不受影响。
CreateCertificate、CreateCertificateRequest 和 CreateRevocationList 现在可以接受 crypto.MessageSigner 签名接口以及 crypto.Signer。这允许这些函数使用实现“一次性”签名接口的签名器(即在签名操作中完成哈希,而不是由调用方先行哈希)。
如果 SubjectKeyId 缺失,CreateCertificate 现在使用截断的 SHA-256 来填充。将 GODEBUG 设置为 x509sha256skid=0 可恢复为使用 SHA-1。
ParseCertificate 现在会拒绝包含带有负 pathLenConstraint 的 BasicConstraints 扩展的证书。
ParseCertificate 现在对使用 ASN.1 T61String 和 BMPString 类型编码的字符串处理更为一致。这可能导致之前被接受的一些格式错误的编码现在被拒绝。
debug/elf 包新增了两个常量:
FilterPackage、PackageExports 和 MergePackageFiles 函数,以及 MergeMode 类型和其常量,均已弃用,因为它们仅用于长期已弃用的 Object 和 Package 机制。
新的 PreorderStack 函数与 Inspect 类似,用于遍历语法树并可控制是否进入子树,但作为便利,它还在每个位置提供了包含该节点的父/封闭节点栈。
ParseDir 函数已弃用。
新的 FileSet.AddExistingFiles 方法允许将现有的 File 添加到 FileSet,或为任意一组 File 构建 FileSet,从而缓解长期运行的应用中与单一全局 FileSet 相关的问题。
Var 现在有一个 Var.Kind 方法,用于将变量分类为以下之一:包级变量、接收者、参数、返回值、局部变量或结构体字段。
新的 LookupSelection 函数用于查找给定名称和接收者类型的字段或方法,类似于现有的 LookupFieldOrMethod,但以 Selection 的形式返回结果。
新的 XOF 接口可由“可扩展输出函数”实现,这类哈希函数具有任意或无限的输出长度,例如 SHAKE。
实现了新的 Cloner 接口的哈希可以返回其内部状态的副本。标准库中所有的 Hash 实现现在都实现了 Cloner。
新的 Hash.Clone 方法实现了 hash.Cloner 接口。
新增的 ReadLinkFS 接口提供在文件系统中读取符号链接的能力。
GroupAttrs 从一个 Attr 值的切片创建一个分组的 Attr。
Record 现在有一个 Source 方法,返回其源位置信息;如果不可用则返回 nil。
新增的辅助函数 FileContentDisposition 用于构建 multipart 的 Content-Disposition 头字段。
LookupMX 和 Resolver.LookupMX 现在会返回看起来像有效 IP 地址的 DNS 名称,也会返回有效的域名。之前如果名称服务器把 IP 地址作为 DNS 名称返回,LookupMX 会根据 RFC 丢弃它,但实际中名称服务器有时会返回这样的 IP 地址。
在 Windows 上,ListenMulticastUDP 现在支持 IPv6 地址。
在 Windows 上现在可以在 os.File 与网络连接之间相互转换。具体来说,FileConn、FilePacketConn 和 FileListener 函数现已实现,返回与打开的文件对应的网络连接或监听器。类似地,TCPConn、UDPConn、UnixConn、IPConn、TCPListener 和 UnixListener 的 File 方法现已实现,返回网络连接的底层 os.File。
新的 CrossOriginProtection 提供对跨站请求伪造(CSRF)的防护,通过拒绝不安全的跨源浏览器请求来实现保护。它使用现代浏览器的 Fetch 元数据,无需令牌或 Cookie,并支持基于来源和基于模式的放行(绕过)。
在 Windows 上,NewFile 现在支持为异步 I/O 打开的句柄(即在 syscall.CreateFile 调用中指定了 syscall.FILE_FLAG_OVERLAPPED)。这些句柄会与 Go 运行时的 I/O 完成端口关联,为由此得到的 File 带来以下好处:
此改进对在 Windows 上通过命名管道通信的应用尤其有利。
注意,某个句柄一次只能关联到一个完成端口。如果传递给 NewFile 的句柄已与某个完成端口关联,则返回的 File 会降级为同步 I/O 模式。在这种情况下,I/O 方法将阻塞操作系统线程,截止/超时方法也不会生效。
DirFS 和 Root.FS 返回的文件系统实现了新的 io/fs.ReadLinkFS 接口。CopyFS 在复制实现了 io/fs.ReadLinkFS 的文件系统时支持符号链接。
Root 类型还支持以下附加方法: Root.Chmod Root.Chown Root.Chtimes Root.Lchown Root.Link Root.MkdirAll Root.ReadFile Root.Readlink Root.RemoveAll Root.Rename Root.Symlink Root.WriteFile
新的 TypeAssert 函数允许将一个 Value 直接转换为指定类型的 Go 值。 这类似于对 Value.Interface 的结果进行类型断言,但可避免不必要的内存分配。
\p{name} 和 \P{name} 字符类语法现在接受名称 Any、ASCII、Assigned、Cn 和 LC,以及像 \p{Letter}(对应 \pL)这样的 Unicode 类别别名。遵循 Unicode TR18,它们现在也使用不区分大小写的名称查找,并忽略空格、下划线和连字符。
通过 AddCleanup 安排的清理函数现在会并发并行执行,这使得在像 unique 包那样的高强度场景下使用清理功能更加可行。注意,如果某个清理函数需要长时间执行或可能阻塞,仍应将其工作转到新的 goroutine 中,以避免阻塞清理队列。
新增的 GODEBUG=checkfinalizers=1 设置有助于发现与 finalizer 和 cleanup 相关的常见问题(如 GC 指南中所述)。在该模式下,运行时会在每次垃圾回收周期运行诊断,并定期将 finalizer 队列和 cleanup 队列的长度报告到 stderr,以便识别运行时间过长的 finalizer 或 cleanup 的问题。更多细节请参见 GODEBUG 文档。
新增的 SetDefaultGOMAXPROCS 函数会将 GOMAXPROCS 设置为运行时的默认值,就好像没有设置 GOMAXPROCS 环境变量一样。当 GOMAXPROCS 环境变量或先前对 GOMAXPROCS 的调用禁用了新的默认值时,这个函数可以用来重新启用该默认值。
针对运行时内部锁的争用的 mutex 配置文件现在会正确地指向导致延迟的临界区的结束位置。这与对 sync.Mutex 值争用时配置文件的行为一致。用于 GODEBUG 的 runtimecontentionstacks 设置(此前可用于对该部分配置文件选择 Go 1.22 至 1.24 的非通常行为)现已移除。
新的 WaitGroup.Go 方法使创建并对 goroutine 进行计数的常见模式更加方便。
新的方法 T.Attr、B.Attr 和 F.Attr 会向测试日志记录一个属性。属性是与测试关联的任意键值对。
例如,在名为 TestF 的测试中,t.Attr("key", "value") 会输出:
=== ATTR TestF key value
使用 -json 标志时,属性会作为新的 "attr" 操作出现。
T、B 和 F 的新方法 Output 提供了一个 io.Writer,写入与 TB.Log 相同的测试输出流。与 TB.Log 一样,输出会缩进,但不会包含文件名和行号。
AllocsPerRun 函数现在在有并行测试运行时会 panic。若有其他测试并行运行,AllocsPerRun 的结果本质上是不稳定的;新的 panic 行为有助于发现此类错误。
MapFS 实现了新的 io/fs.ReadLinkFS 接口。TestFS 如果实现了该接口,会验证 io/fs.ReadLinkFS 的功能。为了避免不受限制的递归,TestFS 将不再跟随符号链接。
新的 CategoryAliases 映射提供对类别别名的访问,例如 "Letter" 对应 "L"。
新增的类别 Cn 和 LC 分别定义了未分配的码点和有大小写区分的字母。它们本来就是 Unicode 定义的一部分,但在早期的 Go 版本中被不小心遗漏。C 类别现在包含了 Cn,这意味着它已将所有未分配的码点纳入其中。
unique 包现在以更积极、更高效且并行的方式回收已驻留(interned)的值。因此,当驻留大量真正唯一的值时,使用 Make 的应用程序更不容易出现内存暴增。
之前,传入 Make 且包含 Handle 的值需要多次垃圾回收周期才能回收,次数与 Handle 值链的深度成正比。现在,这些值一旦不再使用,会在单个回收周期内被及时回收。
如同在 Go 1.24 的发布说明中所述,Go 1.25 需要 macOS 12 Monterey 或更高版本,不再支持更早的系统版本。
Go 1.25 是最后一个包含有缺陷的 32 位 windows/arm 端口(GOOS=windows GOARCH=arm)的版本,该端口将在 Go 1.26 中被移除。
linux/loong64 端口现在支持数据竞争检测器(race detector),可以通过 runtime.SetCgoTraceback 从 C 代码收集回溯信息,并支持使用 internal 链接模式链接 cgo 程序。
linux/riscv64 端口现在支持 plugin 构建模式。GORISCV64 环境变量现在接受一个新值 rva23u64,用于选择 RVA23U64 用户模式应用程序配置文件。