语言变化
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
,它会打印:
|
|
现在,这个程序将打印:
|
|
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
:
|
|
这个程序是不正确的,因为它在检查错误之前使用了 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
。当代码需要同时支持 Signer
和 MessageSigner
时,可以使用此功能。
crypto/ecdsa
新的 ParseRawPrivateKey
、ParseUncompressedPublicKey
函数以及 PrivateKey.Bytes
和 PublicKey.Bytes
方法实现了低级别编码(low-level encodings),取代了使用 crypto/elliptic
或 math/big
函数和方法的需要。
crypto/elliptic
Curve
某些实现中隐藏且未文档化的 Inverse
和 CombinedMult
方法已被移除。
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
CreateCertificate
、CreateCertificateRequest
和 CreateRevocationList
现在可以接受 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
FilterPackage
、PackageExports
和 MergePackageFiles
函数,以及 MergeMode
类型及其常量,都已弃用(deprecated),因为它们仅与早已弃用的 Object
和 Package
机制配合使用。
新的 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
GroupAttrs
从 Attr
值切片创建组属性(group Attr)。
Record
现在有一个 Source
方法,返回其源位置,如果不可用则返回 nil
。
mime/multipart
新的辅助函数 FieldContentDisposition
用于构建多部分 Content-Disposition
头部字段(header fields)。
net
LookupMX
和 Resolver.LookupMX
现在会返回看起来像有效 IP 地址的 DNS 名称,以及有效的域名。以前,如果名称服务器返回 IP 地址作为 DNS 名称,LookupMX
会按照 RFC 的要求将其丢弃。然而,实践中名称服务器有时确实会返回 IP 地址。
在 Windows 上,ListenMulticastUDP
现在支持 IPv6 地址。
在 Windows 上,现在支持 os.File
和网络连接之间的转换。具体来说,FileConn
、FilePacketConn
、FileListener
函数现已实现,允许获取对应于已打开文件的网络连接或监听器。TCPConn.File
、UDPConn.File
、UnixConn.File
、IPConn.File
、TCPListener.File
和 UnixListener.File
方法现在也可用,允许访问连接底层对应的 os.File
。
net/http
新的 CrossOriginProtection
通过拒绝非安全的跨域浏览器请求(cross-origin browser requests) 来实施针对跨站请求伪造(CSRF, Cross-Site Request Forgery) 的保护。它使用现代浏览器的 Fetch 元数据(Fetch metadata),不需要 token 或 cookie,并支持基于来源和基于模式的绕过。
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.Read
、File.Write
、File.ReadAt
和File.WriteAt
) 不会阻塞操作系统线程。 - 支持截止日期方法 (
File.SetDeadline
、File.SetReadDeadline
和File.SetWriteDeadline
)。 此增强对于通过 Windows 上的**命名管道(named pipes)**进行通信的应用程序特别有益。
请注意,一个句柄在同一时间只能与一个完成端口关联。如果提供给 NewFile
的句柄已与完成端口关联,则返回的 File
将降级为同步 I/O 模式(synchronous I/O mode)。在这种情况下,I/O 方法会阻塞操作系统线程,并且截止日期方法无效。
DirFS
和 Root.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)现在接受 Any
、ASCII
、Assigned
、Cn
和 LC
等名称,以及像 \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.Attr
、B.Attr
和 F.Attr
会向测试日志发出一个属性(attribute)。属性是与测试关联的任意键值对。
例如,在名为 TestAttr
的测试中,t.Attr("key", "value")
会输出:
|
|
T
、B
和 F
的新方法 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”。新的类别 Cn
和 LC
分别定义了未分配的码点(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)。