GO 1.25

发布于:2025-06-14 ⋅ 阅读:(19) ⋅ 点赞:(0)

Go 1.25 发布说明(草案)

Go 1.25 尚未发布。 本文档是正在编写中的发布说明。Go 1.25 预计于 2025 年 8 月发布。

语言变更

Go 1.25 中没有影响 Go 程序的语法变更。然而,在语言规范中,“核心类型”(core types)的概念已被移除,代之以专门的描述性文本。更多信息请参阅相关博客文章。

工具

Go 命令

  • go build -asan 选项现在默认在程序退出时执行内存泄露检测。如果 C 分配的内存未被释放,且未被任何其他 C 或 Go 分配的内存引用,将报告错误。可通过在运行程序时设置环境变量 ASAN_OPTIONS=detect_leaks=0 禁用这些新错误报告。
  • Go 发行版将包含更少的预构建工具二进制文件。核心工具链二进制文件(如编译器和链接器)仍会包含,但非 buildtest 操作调用的工具将按需由 go tool 构建和运行。
  • 新增 go.mod ignore 指令,用于指定 go 命令应忽略的目录。匹配包模式(如 all./...)时,go 命令将忽略这些目录及其子目录中的文件,但这些文件仍会包含在模块 zip 文件中。
  • 新增 go doc -http 选项,将启动文档服务器显示请求对象的文档,并在浏览器窗口中打开文档。
  • 新增 go version -m -json 选项,将以 JSON 格式打印嵌入给定 Go 二进制文件中的 runtime/debug.BuildInfo 结构体。
  • 解析模块路径时,go 命令现在支持使用仓库子目录作为模块根路径,语法为 <meta name="go-import" content="root-path vcs repo-url subdir">,表示 root-path 对应版本控制系统 vcsrepo-url 中的 subdir 目录。
  • 新的工作空间包模式 work 匹配工作空间(原称 main)模块中的所有包:在模块模式下指单个工作模块,在工作空间模式下指所有工作空间模块的集合。
  • go 命令更新 go.modgo.work 文件中的 go 行时,不再添加指定当前命令版本的 toolchain 行。

Vet

go vet 命令包含新的分析器:

  • waitgroup:报告对 sync.WaitGroup.Add 的错误调用;
  • hostport:报告使用 fmt.Sprintf("%s:%d", host, port)net.Dial 构造地址的情况(因不兼容 IPv6);建议改用 net.JoinHostPort

运行时

容器感知的 GOMAXPROCS

GOMAXPROCS 的默认行为已更改。在之前的 Go 版本中,GOMAXPROCS 默认值为启动时可用的逻辑 CPU 数量(runtime.NumCPU)。Go 1.25 引入两项变更:

  1. Linux:运行时考虑进程所属 cgroup 的 CPU 带宽限制(如果存在)。若该限制低于可用逻辑 CPU 数量,GOMAXPROCS 将默认设为该限制值。在 Kubernetes 等容器运行时系统中,cgroup CPU 带宽限制通常对应 “CPU limit” 选项。Go 运行时不考虑 “CPU requests” 选项。
  2. 所有操作系统:如果可用逻辑 CPU 数量或 cgroup CPU 带宽限制发生变化,运行时会定期更新 GOMAXPROCS

如果通过 GOMAXPROCS 环境变量或 runtime.GOMAXPROCS 调用手动设置了 GOMAXPROCS,则上述行为自动禁用。也可分别通过 GODEBUG 设置 containermaxprocs=0updatemaxprocs=0 显式禁用。

为支持读取更新的 cgroup 限制,运行时将在进程生命周期内缓存 cgroup 文件的文件描述符。

新的实验性垃圾回收器

新增一个实验性垃圾回收器。该回收器设计通过更好的局部性和 CPU 可扩展性提升标记和扫描小对象的性能。基准测试结果各异,但我们预计在重度使用垃圾回收器的实际程序中,垃圾回收开销可减少 10-40%。

构建时设置 GOEXPERIMENT=greenteagc 可启用新垃圾回收器。我们预计该设计将持续演进和改进。为此,我们鼓励 Go 开发者试用并通过 GitHub issue 分享使用体验(含设计详情和反馈指南)。

未处理 panic 输出的变更

因被恢复(recovered)后又重新引发(repanicked)的未处理 panic 导致程序退出时,打印的消息不再重复 panic 值的文本。

先前,一个使用 panic("PANIC") 引发 panic、恢复该 panic 后又用原值重新引发的程序会输出:
panic: PANIC [recovered]
panic: PANIC
现在该程序将输出:
panic: PANIC [recovered, repanicked]

Linux 上的 VMA 命名

在支持匿名虚拟内存区域 (VMA) 名称的内核(CONFIG_ANON_VMA_NAME)的 Linux 系统上,Go 运行时将为匿名内存映射添加用途上下文注释(如堆内存标记为 [anon: Go: heap])。可通过 GODEBUG 设置 decoratemappings=0 禁用此功能。

编译器

  • Go 1.25 中的编译器和链接器现在使用 DWARF 版本 5 生成调试信息。新版 DWARF 减少了 Go 二进制文件中调试信息所需的空间,并缩短了链接时间(尤其对大型 Go 二进制文件)。构建时设置环境变量 GOEXPERIMENT=nodwarf5 可禁用 DWARF 5 生成(此选项未来可能移除)。
  • 编译器已修复以确保及时执行 nil 指针检查。像下面这样曾成功运行的程序,现在将因 nil 指针异常而 panic:
    package main
    import "os"
    func main() {
        f, err := os.Open("nonExistentFile")
        name := f.Name() // 错误:应在检查 err 后使用 f
        if err != nil {
            return
        }
        println(name)
    }
    
    此程序错误在于检查 err 前使用了 os.Open 的结果。根据 Go 规范,若 error 结果非 nil,则 os.Open 的主要结果可能为 nil 指针。但因编译器 bug,该程序在 Go 1.21 至 1.24 下能运行成功(违反 Go 规范)。在 Go 1.25 中将无法成功运行。若此变更影响您的代码,解决方案是将非 nil 错误检查提前(最好紧接在产生错误的语句后)。
  • 编译器现在能在更多情况下将切片的底层存储分配在栈上,从而提升性能。此变更可能放大错误使用 unsafe.Pointer 的影响(参见 issue 73199)。为定位此类问题,可使用 bisect 工具配合 -compile=variablemake 标志查找引发问题的分配。也可通过 -gcflags=all=-d=variablemakehash=n 禁用所有此类新的栈分配。

链接器

链接器现在接受 -funcalign=N 命令行选项,用于指定函数入口的对齐方式。默认值依平台而定,本版本中未更改。

标准库

新增 testing/synctest 包

新的 testing/synctest 包为测试并发代码提供支持:

  • Test 函数在隔离的 “bubble” 中运行测试函数。在 bubble 内,time 包函数操作模拟时钟。
  • Wait 函数等待当前 bubble 中的所有 goroutine 阻塞。

新增实验性 encoding/json/v2 包

Go 1.25 包含新的实验性 JSON 实现,构建时设置环境变量 GOEXPERIMENT=jsonv2 可启用。

启用后,可使用两个新包:

  • encoding/json/v2encoding/json 包的重大修订版。
  • encoding/json/jsontext 提供 JSON 语法的低级处理。

此外,启用 “jsonv2” GOEXPERIMENT 时:

  • encoding/json 包使用新 JSON 实现。编组(Marshaling)和解组(Unmarshaling)行为不受影响,但包函数返回的错误文本可能变化。
  • encoding/json 包包含许多新选项,可用于配置编组器和解组器。

新实现在许多场景下性能大幅优于现有实现。通常编码性能两者相当,解码性能新实现显著更快。详见 github.com/go-json-experiment/jsonbench 仓库的详细分析。

更多细节参见提案 issue。我们鼓励 encoding/json 用户启用 GOEXPERIMENT=jsonv2 测试程序,以帮助检测与新实现的兼容性问题。

我们预计 encoding/json/v2 的设计将持续演进。鼓励开发者试用新 API 并在提案 issue 中反馈。

库的次要变更

  • archive/tar
    Writer.AddFS 实现现在支持对实现了 io/fs.ReadLinkFS 的文件系统的符号链接。
  • crypto
    新增 MessageSigner 签名接口,供需要自行哈希待签名消息的签名者实现。
    新增 SignMessage 函数,尝试将 Signer 接口更新为 MessageSigner:若成功则使用 MessageSigner.SignMessage 方法,否则使用 Signer.Sign 可用于需同时支持 SignerMessageSigner 的代码。
  • crypto/ecdsa
    新增 ParseRawPrivateKeyParseUncompressedPublicKeyPrivateKey.BytesPublicKey.Bytes 函数及方法,实现低级编码,替代需使用 crypto/ellipticmath/big 函数/方法的需求。
  • crypto/elliptic
    某些 Curve 实现上隐藏且未文档化的 InverseCombinedMult 方法已被移除。
  • crypto/sha3
    新增 SHA3.Clone 方法实现 hash.Cloner
  • crypto/tls
    • 新增 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 服务器现在优先选择支持的最高协议版本,即使它不是客户端最偏好的版本。
  • crypto/x509
    CreateCertificateCreateCertificateRequestCreateRevocationList 现在可接受 crypto.MessageSigner 签名接口和 crypto.Signer。这允许这些函数使用实现 “一次性” 签名接口的签名者(哈希在签名操作中完成,而非由调用方完成)。
    CreateCertificate 现在在 SubjectKeyId 缺失时使用截断的 SHA-256 填充。GODEBUG 设置 x509sha256skid=0 可恢复为 SHA-1。
  • debug/elf
    为 RISC-V ELF 解析新增两个常量:PT_RISCV_ATTRIBUTESSHT_RISCV_ATTRIBUTES
  • go/ast
    FilterPackagePackageExportsMergePackageFiles 函数及 MergeMode 类型与其常量均已弃用,因为它们仅用于长期弃用的 ObjectPackage 机制。
    新增 PreorderStack 函数,类似 Inspect 遍历语法树并提供对子树下降的控制,但为方便起见,它在每个点还提供封闭节点的堆栈。
  • go/parser
    弃用 ParseDir 函数。
  • go/token
    新增 FileSet.AddExistingFiles 方法,支持将现有 File 添加到 FileSet,或为任意 File 集合构造 FileSet,缓解了在长生命周期应用中单一全局 FileSet 相关的问题。
  • go/types
    Var 新增 Var.Kind 方法,将变量分类为:包级变量、接收器、参数、结果、局部变量或结构体字段。
    新增 LookupSelection 函数,按名称和接收器类型查找字段或方法(类似现有的 LookupFieldOrMethod),但以 Selection 形式返回结果。
  • hash
    • 新增 XOF 接口,可由 “可扩展输出函数”(如 SHAKE)实现(具有任意或无限输出长度的哈希函数)。
    • 实现新 Cloner 接口的哈希可返回其状态的副本。所有标准库 Hash 实现现在均实现 Cloner
  • hash/maphash
    新增 Hash.Clone 方法实现 hash.Cloner
  • io/fs
    新增 ReadLinkFS 接口,提供读取文件系统中符号链接的能力。
  • log/slog
    • GroupAttrsAttr 值切片创建分组 Attr
    • Record 新增 Source 方法,返回其源位置(若不可用则返回 nil)。
  • mime/multipart
    新增辅助函数 FieldContentDisposition 构建 multipart Content-Disposition 头字段。
  • net
    • LookupMXResolver.LookupMX 现在返回看似有效 IP 地址的 DNS 名称以及有效域名。先前若名称服务器返回 IP 地址作为 DNS 名称,LookupMX 会按 RFC 要求丢弃它。但实践中名称服务器有时确实返回 IP 地址。
    • WindowsListenMulticastUDP 现在支持 IPv6 地址。
    • Windows:现在支持 os.File 与网络连接之间的转换。具体而言:
      • 实现了 FileConnFilePacketConnFileListener 函数,允许获取与打开文件对应的网络连接或监听器。
      • TCPConn.FileUDPConn.FileUnixConn.FileIPConn.FileTCPListener.FileUnixListener.File 方法现在也可用,允许访问连接的底层 os.File
  • net/http
    新增 CrossOriginProtection 实现跨站请求伪造 (CSRF) 防护,通过拒绝不安全的跨域浏览器请求实现。它使用现代浏览器 Fetch 元数据,无需令牌或 cookie,并支持基于来源和模式的绕过。
  • os
    • WindowsNewFile 现在支持为异步 I/O 打开的句柄(即在 syscall.CreateFile 调用中指定了 syscall.FILE_FLAG_OVERLAPPED)。这些句柄与 Go 运行时的 I/O 完成端口关联,为生成的 File 带来以下优势:
      • I/O 方法(File.ReadFile.WriteFile.ReadAtFile.WriteAt)不会阻塞 OS 线程。
      • 支持截止时间方法(File.SetDeadlineFile.SetReadDeadlineFile.SetWriteDeadline)。
        此增强对在 Windows 上通过命名管道通信的应用程序尤其有益。

      注意:一个句柄一次只能关联一个完成端口。若提供给 NewFile 的句柄已关联完成端口,返回的 File 将降级为同步 I/O 模式(此时 I/O 方法会阻塞 OS 线程,且截止时间方法无效)。

    • DirFSRoot.FS 返回的文件系统实现了新的 io/fs.ReadLinkFS 接口。当复制实现 io/fs.ReadLinkFS 的文件系统时,CopyFS 支持符号链接。
    • Root 类型新增以下方法:
      Root.ChmodRoot.ChownRoot.ChtimesRoot.LchownRoot.LinkRoot.MkdirAllRoot.ReadFileRoot.ReadlinkRoot.RemoveAllRoot.RenameRoot.SymlinkRoot.WriteFile
  • reflect
    新增 TypeAssert 函数,允许将 Value 直接转换为给定类型的 Go 值。这类似于对 Value.Interface 结果使用类型断言,但避免了不必要的内存分配。
  • regexp/syntax
    \p{name}\P{name} 字符类语法现在接受名称 AnyASCIIAssignedCnLC,以及 Unicode 类别别名(如 \p{Letter} 对应 \pL)。遵循 Unicode TR18,它们现在也使用不区分大小写的名称查找,忽略空格、下划线和连字符。
  • runtime
    • AddCleanup 调度的清理函数现在并发并行执行,使清理更适用于重负载场景(如 unique 包)。注意单个清理若需长时间执行或阻塞,仍应将其工作分流到新 goroutine,以免阻塞清理队列。
    • 设置 GODEBUG=checkfinalizers=1 时,运行时将在每个垃圾回收周期运行诊断以查找程序使用终结器(finalizers)和清理的常见问题(如 GC 指南所述)。在此模式下,运行时还会定期将终结器和清理队列长度报告到 stderr,以帮助识别长时间运行的终结器/清理问题。
    • 新增 SetDefaultGOMAXPROCS 函数,将 GOMAXPROCS 设为运行时默认值(如同未设置 GOMAXPROCS 环境变量)。若 GOMAXPROCS 环境变量或先前 GOMAXPROCS 调用禁用了新 GOMAXPROCS 默认行为,此函数可用于重新启用它。
  • runtime/pprof
    针对运行时内部锁竞争的互斥锁分析(mutex profile)现在正确指向导致延迟的临界区末尾。这使该部分分析的行为与对 sync.Mutex 值竞争的分析保持一致。允许选择 Go 1.22 至 1.24 中此部分分析特殊行为的 GODEBUG 设置 runtimecontentionstacks 现已移除。
  • runtime/trace
    新增 FlightRecorder(飞行记录器),提供轻量级方式在特定时刻捕获最近几秒执行的跟踪数据。发生重大事件时,程序可调用 FlightRecorder.WriteTo 快照可用跟踪数据。FlightRecorderConfig 可配置 FlightRecorder 捕获的时间长度和数据量。
  • sync
    WaitGroup 新增 WaitGroup.Go 方法,使创建和计数 goroutine 的常见模式更便捷。
  • testing
    • 新增方法 T.AttrB.AttrF.Attr,向测试日志发出属性(attribute)。属性是与测试关联的任意键值对。
      例如,在名为 TestAttr 的测试中,t.Attr("key", "value") 输出:
      === ATTR TestAttr key value
    • TBFOutput 方法提供 io.Writer,写入与 TB.Log 相同的测试输出流,但省略文件和行号。
    • 若有并行测试运行,AllocsPerRun 函数现在会 panic。AllocsPerRun 的结果在其他测试运行时本质上是不可靠的。新的 panic 行为有助于捕获此类错误。
  • testing/fstest
    • MapFS 实现新的 io/fs.ReadLinkFS 接口。
    • 若实现 io/fs.ReadLinkFS 接口,TestFS 将验证其功能。
    • TestFS 不再遵循符号链接以避免无限递归。
  • unicode
    • 新增 CategoryAliases 映射,提供对类别别名(如 “Letter” 对应 “L”)的访问。
    • 新增类别 Cn(未分配码点)和 LC(大小写字母)。这些始终由 Unicode 定义,但在早期 Go 版本中被无意遗漏。
    • C 类别现在包含 Cn(即添加了所有未分配码点)。
  • unique
    • unique 包现在更积极、更高效且并行地回收(reclaim)内部值(interned values)。因此,在大量真正唯一的值被内部化时,使用 Make 的应用程序现在更少遇到内存爆炸问题。
    • 传递给 Make 的包含 Handle 的值,先前需要多次垃圾回收周期才能回收(与 Handle 值链的深度成正比)。现在一旦不再使用,它们将在单个周期中被及时回收。

移植

Darwin

如 Go 1.24 发布说明所宣布,Go 1.25 要求 macOS 12 Monterey 或更高版本;对先前版本的支持已终止。

Windows

Go 1.25 是包含已损坏的 32 位 windows/arm 移植(GOOS=windows GOARCH=arm)的最后一个版本。它将在 Go 1.26 中移除。

RISC-V

  • linux/riscv64 移植现在支持 plugin 构建模式。
  • GORISCV64 环境变量现在接受新值 rva23u64,用于选择 RVA23U64 用户模式应用程序配置文件。