语言变化

Go 1.25 中没有任何影响 Go 程序的语言变更

运行时

容器 GOMAXPROCS 感知

在 Linux 上,Go 运行时会考虑其进程所在的 cgroup(如果有的话)的 CPU 限制。如果 CPU 限制低于可用的逻辑 CPU 数量,那么 GOMAXPROCS 的默认值将设定为这个较低的限制。在像 Kubernetes 这样的容器运行时系统中,cgroup 的 CPU 限制通常对应于“CPU limit”选项。Go 运行时不考虑“CPU requests”选项

在所有操作系统上,如果可用的逻辑 CPU 数量或 cgroup CPU 限制发生变化,运行时会定期更新 GOMAXPROCS

这两个行为会在你手动设置 GOMAXPROCS 的情况下自动禁用,无论是通过 GOMAXPROCS 环境变量还是调用 runtime.GOMAXPROCS 函数。你也可以通过设置 GODEBUG 为 containermaxprocs=0 和 updatemaxprocs=0 来分别明确禁用它们。

实验性垃圾收集器(GreenTea GC)

一个新的垃圾回收器现在作为实验性功能推出。这个垃圾回收器的设计通过**更好的局部性(locality)和 CPU 可伸缩性(scalability),提升了小对象标记(marking)和扫描(scanning)**的性能。基准测试结果各异,但我们预期在那些大量使用垃圾回收器的实际程序中,垃圾回收开销能减少 10% 到 40%。

可以通过在构建时设置环境变量 GOEXPERIMENT=greenteagc 来启用这个新的垃圾回收器。我们预期其设计将继续演进和改进。为此,我们鼓励 Go 开发者试用它并反馈他们的体验。有关其设计细节和反馈方式,请参阅相关的 提案

未处理 panic 输出的变更

当程序因一个被 recover 后又重新 panic 的未处理 panic 而退出时,其打印的信息将不再重复 panic 值(panic value)的文本。

以前,一个程序如果发生 panic("PANIC"),然后 recover 了这个 panic,接着又用原始值重新 panic,它会打印:

1
2
panic: PANIC [recovered]
  panic: PANIC

现在,这个程序将打印:

1
panic: PANIC [recovered, repanicked]

Linux 上的 VMA 命名

在支持匿名虚拟内存区域(VMA)命名的 Linux 系统上(需要内核配置 CONFIG_ANON_VMA_NAME),Go 运行时将用其用途相关的上下文来**标注(annotate)**匿名内存映射。例如,堆内存会显示为 [anon: Go: heap]。这可以通过设置 GODEBUG=decoratemappings=0 来禁用。

编译器

Go 1.25 中的编译器和链接器现在生成使用 DWARF 版本 5 的调试信息。 新的 DWARF 版本减少了 Go 二进制文件中调试信息所需的空间,并缩短了链接时间,特别是对于大型 Go 二进制文件。通过在构建时设置环境变量 GOEXPERIMENT=nodwarf5 可以禁用 DWARF 5 的生成(目前是这样,此选项可能会在未来的 Go 版本中移除)。

编译器已修复,以确保空指针检查能够及时执行。 像下面这样以前能成功执行的程序,现在会因空指针异常(nil-pointer exception)而 panic

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main

import "os"

func main() {
    f, err := os.Open("nonExistentFile")
    name := f.Name() // 在此处使用 f 可能会导致空指针解引用
    if err != nil {
        return
    }
    println(name)
}

这个程序是不正确的,因为它在检查错误之前使用了 os.Open 的结果。如果错误结果非空,os.Open 的主要结果可能是一个空指针。但由于一个编译器错误,这个程序在 Go 1.21 到 1.24 版本中曾成功运行(违反了 Go 规范)。它在 Go 1.25 中将不再成功运行。如果此更改影响了你的代码,解决方案是在代码中更早地进行非空错误检查,最好是紧跟在产生错误的代码语句之后。

编译器现在可以在更多情况下在栈上为切片(slices)分配底层存储(backing store),这提高了性能。 这一更改可能会放大不正确 unsafe.Pointer 用法的影响,例如参见 issue 73199。为了追查这些问题,可以使用 bisect 工具,并结合 -compile=variablemake 标志来查找导致问题的分配。所有这类新的栈分配也可以通过使用 -gcflags=all=-d=variablemakehash=n 来关闭。

链接器

现在,链接器支持一个命令行选项:-funcalign=N。这个选项用于指定函数入口的对齐方式。默认值是根据平台而定的,在此版本中保持不变。

标准库

新的 testing/synctest

新的 testing/synctest 包提供了对**并发代码(concurrent code)**进行测试的支持。

Test 函数在一个隔离的“气泡(bubble)”中运行一个测试函数。在这个气泡内部,time 包的函数操作在一个**模拟时钟(fake clock)**上。

Wait 函数会等待当前气泡中的所有 goroutine 都进入阻塞状态。

新的实验性 encoding/json/v2

Go 1.25 包含了一个新的、实验性的 JSON 实现,可以通过在构建时设置环境变量 GOEXPERIMENT=jsonv2 来启用。

启用后,将提供两个新包:

  • encoding/json/v2 包是 encoding/json 包的一个重大修订版本。
  • encoding/json/jsontext 包提供了更底层的 JSON 语法处理能力。

此外,当 “jsonv2” GOEXPERIMENT 被启用时:

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

在许多场景下,新实现的性能比现有实现有了显著提升。通常情况下,编码性能在两种实现之间是持平的,而新实现的解码速度则显著更快。有关更详细的分析,请参阅 github.com/go-json-experiment/jsonbench 仓库。

欲了解更多详情,请参阅 提案 issue

我们鼓励 encoding/json 的用户在启用 GOEXPERIMENT=jsonv2 的情况下测试他们的程序,以帮助检测新实现可能存在的任何兼容性问题。

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

好的,我已经按照你的要求,将“库的次要变更”部分重新排版,使用 ### 作为主标题,并使用 #### 作为各个子项(包名)的标题,同时保持技术用词的准确性:

库的次要变更

archive/tar

Writer.AddFS 的实现现在支持实现 io/fs.ReadLinkFS 接口的文件系统中的符号链接(symbolic links)

crypto

MessageSigner 是一个新的签名接口,可由希望自行**哈希(hash)**待签名消息的签名器实现。同时引入了一个新函数 SignMessage,它尝试将 Signer 接口更新为 MessageSigner。如果更新成功,则使用 MessageSigner.SignMessage 方法;否则,使用 Signer.Sign。当代码需要同时支持 SignerMessageSigner 时,可以使用此功能。

crypto/ecdsa

新的 ParseRawPrivateKeyParseUncompressedPublicKey 函数以及 PrivateKey.BytesPublicKey.Bytes 方法实现了低级别编码(low-level encodings),取代了使用 crypto/ellipticmath/big 函数和方法的需要。

crypto/elliptic

Curve 某些实现中隐藏且未文档化的 InverseCombinedMult 方法已被移除。

crypto/sha3

新的 SHA3.Clone 方法实现了 hash.Cloner 接口。

crypto/tls

新的 ConnectionState.CurveID 字段暴露了用于建立连接的密钥交换机制(key exchange mechanism)

新的 Config.GetEncryptedClientHelloKeys 回调函数可用于设置 EncryptedClientHelloKeys,供服务器在客户端发送加密客户端Hello扩展(Encrypted Client Hello extension时使用。

根据 RFC 9155,TLS 1.2 握手中现在禁止使用 SHA-1 签名算法。可以通过 tlssha1=1 这个 GODEBUG 选项重新启用。

当启用 FIPS 140-3 模式时,TLS 1.2 中现在强制要求扩展主密钥(Extended Master Secret),并允许使用 Ed25519 和 X25519MLKEM768。

TLS 服务器现在会优先选择支持的最高协议版本,即使它不是客户端最优先的协议版本。

crypto/x509

CreateCertificateCreateCertificateRequestCreateRevocationList 现在可以接受 crypto.MessageSigner 签名接口以及 crypto.Signer。这允许这些函数使用实现“一次性签名(one-shot)”接口的签名器,其中 哈希(hashing) 作为签名操作的一部分完成,而不是由调用者完成。

CreateCertificate 现在在 SubjectKeyId 缺失时使用截断的 SHA-256来填充。GODEBUG 设置 x509sha256skid=0 可以恢复到 SHA-1。

debug/elf

debug/elf 包新增了两个常量:

  • PT_RISCV_ATTRIBUTES
  • SHT_RISCV_ATTRIBUTES 用于 RISC-V ELF 解析。

go/ast

FilterPackagePackageExportsMergePackageFiles 函数,以及 MergeMode 类型及其常量,都已弃用(deprecated),因为它们仅与早已弃用的 ObjectPackage 机制配合使用。

新的 PreorderStack 函数,与 Inspect 类似,遍历语法树(syntax tree)并提供对进入子树的控制,但为了方便,它还在每个点提供了包含节点栈(stack of enclosing nodes)

go/parser

ParseDir 函数已弃用(deprecated)

go/token

新的 FileSet.AddExistingFiles 方法允许将现有 File 添加到 FileSet 中,或者为任意 File 集合构造 FileSet,从而缓解了长期运行应用程序中单个全局 FileSet 相关的问题。

go/types

Var 现在有一个 Var.Kind 方法,将变量分类为:包级变量、接收器(receiver)、参数、结果、局部变量或结构体字段。

新的 LookupSelection 函数根据给定名称和接收器类型查找字段或方法,类似于现有的 LookupFieldOrMethod 函数,但以 Selection 的形式返回结果。

hash

新的 XOF 接口可由“可扩展输出函数(extendable output functions)”实现,这些是具有任意或无限输出长度的哈希函数,例如 SHAKE。

实现新 Cloner 接口的哈希函数可以返回其状态的副本。所有标准库的 Hash 实现现在都实现了 Cloner

hash/maphash

新的 Hash.Clone 方法实现了 hash.Cloner

io/fs

新的 ReadLinkFS 接口提供了在文件系统中读取**符号链接(symbolic links)**的能力。

log/slog

GroupAttrsAttr 值切片创建组属性(group Attr)

Record 现在有一个 Source 方法,返回其源位置,如果不可用则返回 nil

mime/multipart

新的辅助函数 FieldContentDisposition 用于构建多部分 Content-Disposition 头部字段(header fields)

net

LookupMXResolver.LookupMX 现在会返回看起来像有效 IP 地址的 DNS 名称,以及有效的域名。以前,如果名称服务器返回 IP 地址作为 DNS 名称,LookupMX 会按照 RFC 的要求将其丢弃。然而,实践中名称服务器有时确实会返回 IP 地址。

在 Windows 上,ListenMulticastUDP 现在支持 IPv6 地址。

在 Windows 上,现在支持 os.File 和网络连接之间的转换。具体来说,FileConnFilePacketConnFileListener 函数现已实现,允许获取对应于已打开文件的网络连接或监听器。TCPConn.FileUDPConn.FileUnixConn.FileIPConn.FileTCPListener.FileUnixListener.File 方法现在也可用,允许访问连接底层对应的 os.File

net/http

新的 CrossOriginProtection 通过拒绝非安全的跨域浏览器请求(cross-origin browser requests) 来实施针对跨站请求伪造(CSRF, Cross-Site Request Forgery) 的保护。它使用现代浏览器的 Fetch 元数据(Fetch metadata),不需要 tokencookie,并支持基于来源和基于模式的绕过。

os

在 Windows 上,NewFile 现在支持为异步 I/O(asynchronous I/O) 而打开的句柄(即在 syscall.CreateFile 调用中指定了 syscall.FILE_FLAG_OVERLAPPED)。这些句柄与 Go 运行时的 I/O 完成端口(I/O completion port) 相关联,这为生成的 File 带来了以下好处:

  • I/O 方法 (File.ReadFile.WriteFile.ReadAtFile.WriteAt) 不会阻塞操作系统线程。
  • 支持截止日期方法 (File.SetDeadlineFile.SetReadDeadlineFile.SetWriteDeadline)。 此增强对于通过 Windows 上的**命名管道(named pipes)**进行通信的应用程序特别有益。

请注意,一个句柄在同一时间只能与一个完成端口关联。如果提供给 NewFile 的句柄已与完成端口关联,则返回的 File 将降级为同步 I/O 模式(synchronous I/O mode)。在这种情况下,I/O 方法会阻塞操作系统线程,并且截止日期方法无效。

DirFSRoot.FS 返回的文件系统实现了新的 io/fs.ReadLinkFS 接口。CopyFS 在复制实现 io/fs.ReadLinkFS 的文件系统时支持符号链接(symlinks)

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

reflect

新的 TypeAssert 函数允许将 Value 直接转换为给定类型的 Go 值。这类似于对 Value.Interface 的结果使用类型断言(type assertion),但避免了不必要的内存分配。

regexp/syntax

\p{name}\P{name} **字符类语法(character class syntaxes)现在接受 AnyASCIIAssignedCnLC 等名称,以及像 \p{Letter} 这样的 Unicode 类别别名(alias)代表 \pL。根据 Unicode TR18,它们现在也使用不区分大小写(case-insensitive)**的名称查找,并忽略空格、下划线和连字符。

runtime

通过 AddCleanup 调度的清理函数现在并发(concurrently) 并行执行,这使得清理在诸如 unique 包这样的重度使用场景中更具可行性。请注意,如果单个清理函数必须长时间执行或阻塞,它们仍应将其工作分流到新的 goroutine 中,以避免阻塞清理队列。

当设置 GODEBUG=checkfinalizers=1 时,运行时会在每个垃圾回收周期运行诊断,以查找程序在使用 finalizer清理函数(cleanups) 时常见的,例如 GC 指南 中描述的问题。在此模式下,运行时还会定期向标准错误(stderr)报告 finalizer 和清理队列的长度,以帮助识别长时间运行的 finalizer 或清理函数引起的问题。

新的 SetDefaultGOMAXPROCS 函数将 GOMAXPROCS 设置为运行时的默认值,如同没有设置 GOMAXPROCS 环境变量一样。这对于启用新的 GOMAXPROCS 默认行为非常有用,即使它曾被 GOMAXPROCS 环境变量或先前对 GOMAXPROCS 的调用禁用。

runtime/pprof

关于运行时内部锁竞争(contention)互斥锁 profile(mutex profile) 现在能正确指向导致延迟的临界区(critical section) 的末尾。这与 sync.Mutex 值竞争的 profile 行为相匹配。GODEBUG 中的 runtimecontentionstacks 设置(该设置允许在 Go 1.22 到 1.24 中选择此部分 profile 的异常行为)现已移除。

runtime/trace

新的 FlightRecorder 提供了一种轻量级方式,用于在特定时间点捕获最后几秒执行的跟踪(trace)。当发生重要事件时,程序可以调用 FlightRecorder.WriteTo快照(snapshot) 可用的跟踪数据。FlightRecorder 捕获的时间长度和数据量可以在 FlightRecorderConfig 中配置。

sync

WaitGroup 的新方法 WaitGroup.Go 使创建和计数 goroutine 的常见模式更加方便。

testing

新的方法 T.AttrB.AttrF.Attr 会向测试日志发出一个属性(attribute)。属性是与测试关联的任意键值对。

例如,在名为 TestAttr 的测试中,t.Attr("key", "value") 会输出:

1
=== ATTR  TestAttr key value

TBF 的新方法 Output 提供了一个 io.Writer,它会写入与 TB.Log 相同的测试输出流,但省略了文件和行号。

如果并行测试正在运行,AllocsPerRun 函数现在会 panic。如果其他测试正在运行,AllocsPerRun 的结果本质上是不稳定的(flaky)。新的 panic 行为有助于发现此类 bug。

testing/fstest

MapFS 实现了新的 io/fs.ReadLinkFS 接口。如果实现了 io/fs.ReadLinkFS 接口,TestFS 将验证其功能。TestFS 将不再跟踪符号链接(symlinks)以避免无界递归(unbounded recursion)

unicode

新的 CategoryAliases 映射提供了对类别别名名称的访问,例如“Letter”代表“L”。新的类别 CnLC 分别定义了未分配的码点(codepoints)和大小写字母(cased letters)。这些在 Unicode 中一直有定义,但 Go 的早期版本中无意中遗漏了。C 类别现在包含 Cn,这意味着它添加了所有未分配的码点。

unique

unique 包现在更积极、更高效地并行(in parallel)回收内部化(interned)的值。因此,当大量真正独一无二的值被内部化时,使用 Make 的应用程序现在更不容易出现内存膨胀(memory blow-up)

以前,传递给 Make 且包含 Handles 的值需要多个垃圾回收周期才能被回收,这与 Handle 值链的深度成正比。现在,一旦不再使用,它们会在单个周期内及时被回收。

移植(Ports)

Darwin

正如 Go 1.24 发行说明中所宣布(announced) 的,Go 1.25 需要 macOS 12 Monterey 或更高版本;对先前版本的支持已停止。

Windows

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

RISC-V

linux/riscv64 移植现在支持 plugin 构建模式(build mode)

GORISCV64 环境变量现在接受一个新值 rva23u64,它选择 RVA23U64 用户模式应用程序配置文件(user-mode application profile)


翻译自: https://tip.golang.org/doc/go1.25