Go 1.23 发布说明
Go 1.23 简介
最新的 Go 版本 1.23 在 Go 1.22 发布六个月后发布。其大部分更改都体现在工具链、运行时和库的实现上。与往常一样,该版本保持了 Go 1 兼容性承诺。我们预计几乎所有 Go 程序都将像以前一样继续编译和运行。
语言更改
“for-range” 循环中的“range” 子句现在接受以下类型的迭代器函数
func(func() bool)
func(func(K) bool)
func(func(K, V) bool)
作为 range 表达式。迭代器参数函数的调用会生成“for-range”循环的迭代值。有关详细信息,请参阅 iter
包文档、语言规范 和 关于函数类型的 Range 博客文章。有关动机,请参阅 2022 年 “range-over-func” 讨论。
Go 1.23 包含对 泛型类型别名 的预览支持。使用 GOEXPERIMENT=aliastypeparams
构建工具链可以在包中启用此功能。(跨包边界使用泛型别名类型尚不受支持。)
工具
遥测
从 Go 1.23 开始,Go 工具链可以收集使用情况和故障统计信息,帮助 Go 团队了解 Go 工具链的使用方式及其工作情况。我们将这些统计信息称为 Go 遥测。
Go 遥测是一个选择加入系统,由 go
telemetry
命令 控制。默认情况下,工具链程序会收集计数器文件中的统计信息,这些文件可以在本地检查,但在其他情况下未使用(go
telemetry
local
)。
为了帮助我们保持 Go 的良好运行并了解 Go 的使用情况,请考虑通过运行 go
telemetry
on
选择加入 Go 遥测。在此模式下,匿名计数器报告将每周上传到 telemetry.go.dev,在那里它们会被聚合到图表中,并且也可以供任何 Go 贡献者或想要分析数据的用户下载。有关 Go 遥测系统的更多详细信息,请参阅“Go 遥测”。
Go 命令
设置 GOROOT_FINAL
环境变量不再有任何效果(#62047)。将 go
命令安装到 $GOROOT/bin/go
以外的位置的发行版应安装符号链接,而不是重新定位或复制 go
二进制文件。
新的 go
env
-changed
标志导致命令仅打印其有效值与在空环境中且未先前使用 -w
标志获得的默认值不同的设置。
新的 go
mod
tidy
-diff
标志导致命令不修改文件,而是将必要的更改打印为统一差异。如果需要更新,则退出时返回非零代码。
go
list
-m
-json
命令现在包含新的 Sum
和 GoModSum
字段。这类似于 go
mod
download
-json
命令的现有行为。
go.mod
和 go.work
中新的 godebug
指令声明一个 GODEBUG 设置,以应用于正在使用的工作模块或工作区。
Vet
go vet
子命令现在包含 stdversion 分析器,该分析器会标记对对于引用文件中有效的 Go 版本来说过新的符号的引用。(有效版本由文件包含的 go.mod
文件中的 go
指令以及文件中的任何 //go:build
约束 确定。)
例如,它将为从其 go.mod
文件指定 go 1.21
的模块中的文件引用 reflect.TypeFor
函数(在 go1.22 中引入)报告诊断信息。
Cgo
cmd/cgo
支持新的 -ldflags
标志,用于将标志传递给 C 链接器。go
命令会自动使用它,避免使用非常大的 CGO_LDFLAGS
时出现“参数列表过长”错误。
Trace
trace
工具现在更好地容忍部分损坏的跟踪,因为它尝试恢复它可以获取的跟踪数据。当查看在程序崩溃期间收集的跟踪时,此功能特别有用,因为在大多数情况下,导致崩溃之前的跟踪数据现在 可以恢复。
运行时
运行时在发生未处理的 panic 或其他致命错误后打印的回溯现在将错误消息的第二行和后续行缩进(例如,panic 的参数)一个制表符,以便可以明确地区分第一个 goroutine 的堆栈跟踪。有关讨论,请参阅 #64590。
编译器
使用 Profile Guided Optimization(PGO) 构建的构建时间开销已大大减少。以前,大型构建可能会因为启用 PGO 而导致构建时间增加 100% 以上。在 Go 1.23 中,开销应在个位百分比范围内。
Go 1.23 中的编译器现在可以重叠函数中在不相交区域访问的局部变量的堆栈帧槽,这减少了 Go 应用程序的堆栈使用量。
对于 386 和 amd64,编译器将使用来自 PGO 的信息来对齐循环中的某些热点块。这以额外增加 0.1% 的文本和二进制文件大小为代价,将性能提高了额外 1-1.5%。这目前仅在 386 和 amd64 上实现,因为它在其他平台上没有显示出改进。可以使用 -gcflags=[<packages>=]-d=alignhot=0
禁用热点块对齐。
链接器
链接器现在不允许使用 //go:linkname
指令引用标准库(包括运行时)中未在其定义上标记为 //go:linkname
的内部符号。类似地,链接器不允许从汇编代码引用此类符号。为了向后兼容,在大型开源代码库中找到的 //go:linkname
的现有用法仍然受支持。任何对标准库内部符号的新引用都将被禁止。
链接器命令行标志 -checklinkname=0
可用于禁用此检查,用于调试和实验目的。
在构建动态链接的 ELF 二进制文件(包括 PIE 二进制文件)时,新的 -bindnow
标志启用立即函数绑定。
标准库
计时器更改
Go 1.23 对 time.Timer
和 time.Ticker
的实现进行了两次重大更改。
首先,程序不再引用的 Timer
和 Ticker
立即有资格进行垃圾回收,即使尚未调用其 Stop
方法。早期版本的 Go 不会在 Timer
触发后才回收未停止的 Timer
,并且从不回收未停止的 Ticker
。
其次,与 Timer
或 Ticker
关联的计时器通道现在是无缓冲的,容量为 0。此更改的主要影响是 Go 现在保证对于对 Reset
或 Stop
方法的任何调用,在该调用之前准备的任何陈旧值都不会在调用后发送或接收。早期版本的 Go 使用具有一个元素缓冲区的通道,这使得难以正确使用 Reset
和 Stop
。此更改的一个可见效果是,计时器通道的 len
和 cap
现在返回 0 而不是 1,这可能会影响轮询长度以确定在计时器通道上接收是否会成功的程序。此类代码应改用非阻塞接收。
只有当主 Go 程序位于使用 Go 1.23.0 或更高版本的 go.mod
go
行的模块中时,这些新行为才会启用。当 Go 1.23 构建旧程序时,旧行为仍然有效。新的 GODEBUG 设置 asynctimerchan=1
可用于即使程序在其 go.mod
文件中命名 Go 1.23.0 或更高版本时也恢复为异步通道行为。
新的唯一包
新的 unique
包提供了规范化值(如“内部化”或“哈希合并”)的功能。
任何可比较类型的值都可以使用新的 Make[T]
函数进行规范化,该函数以 Handle[T]
的形式生成对值的规范副本的引用。如果用于生成句柄的值相等,则两个 Handle[T]
相等,从而允许程序对值进行重复数据删除并减少其内存占用。比较两个 Handle[T]
值是高效的,可以简化为简单的指针比较。
迭代器
新的 iter
包提供了用于处理用户定义迭代器的基本定义。
slices
包添加了一些与迭代器一起使用的函数。
- All 返回一个迭代器,用于遍历切片的索引和值。
- Values 返回一个迭代器,用于遍历切片的元素。
- Backward 返回一个迭代器,用于反向遍历切片。
- Collect 将迭代器中的值收集到一个新的切片中。
- AppendSeq 将迭代器中的值追加到现有的切片中。
- Sorted 将迭代器中的值收集到一个新的切片中,然后对该切片进行排序。
- SortedFunc 与
Sorted
类似,但使用比较函数。 - SortedStableFunc 与
SortFunc
类似,但使用稳定的排序算法。 - Chunk 返回一个迭代器,用于遍历切片中最多 n 个元素的连续子切片。
新的 maps
包添加了一些与迭代器一起使用的函数。
- All 返回一个迭代器,用于遍历映射中的键值对。
- Keys 返回一个迭代器,用于遍历映射中的键。
- Values 返回一个迭代器,用于遍历映射中的值。
- Insert 将迭代器中的键值对添加到现有的映射中。
- Collect 将迭代器中的键值对收集到一个新的映射中并返回它。
新的 structs 包
新的 structs
包提供了用于结构体字段的类型,这些类型可以修改包含结构体类型的属性,例如内存布局。
在此版本中,唯一此类类型是 HostLayout
,它指示具有该类型字段的结构体具有符合主机平台期望的布局。HostLayout 应该用于传递给、从或通过传递给/来自主机 API 的指针访问的类型。如果没有此标记,语言规范不保证结构体布局顺序,尽管从 Go 1.23 开始,主机和语言布局恰好匹配。
库的次要更改
archive/tar
如果 FileInfoHeader
的参数实现了新的 FileInfoNames
接口,则将使用接口方法设置文件头的 Uname/Gname。这允许应用程序覆盖系统相关的 Uname/Gname 查找。
crypto/tls
TLS 客户端现在支持加密客户端问候 草案规范。可以通过将 Config.EncryptedClientHelloConfigList
字段设置为要连接到的主机的编码 ECHConfigList 来启用此功能。
QUIC 实现使用的 QUICConn
类型包括关于会话恢复状态的新事件报告,并提供了一种方法,使 QUIC 层能够将数据添加到会话票证和会话缓存条目中。
3DES 密码套件已从 Config.CipherSuites
为空时使用的默认列表中删除。可以通过将 tls3des=1
添加到 GODEBUG 环境变量中来恢复默认值。
当 Config.CurvePreferences
为空时,实验性后量子密钥交换机制 X25519Kyber768Draft00 现在默认启用。可以通过将 tlskyber=0
添加到 GODEBUG 环境变量中来恢复默认值。
Go 1.23 更改了 X509KeyPair
和 LoadX509KeyPair
的行为,以填充返回的 Certificate
的 Certificate.Leaf
字段。为该行为添加了新的 x509keypairleaf
GODEBUG 设置。
crypto/x509
CreateCertificateRequest
现在正确支持 RSA-PSS 签名算法。
CreateCertificateRequest
和 CreateRevocationList
现在使用签名者的公钥验证生成的签名。如果签名无效,则返回错误。自 Go 1.16 以来,这已成为 CreateCertificate
的行为。
x509sha1
GODEBUG 设置 将在下一个 Go 主版本(Go 1.24)中删除。这意味着 crypto/x509
将不再支持验证使用基于 SHA-1 的签名算法的证书上的签名。
新的 ParseOID
函数解析点编码的 ASN.1 对象标识符字符串。OID
类型现在实现了 encoding.BinaryMarshaler
、encoding.BinaryUnmarshaler
、encoding.TextMarshaler
、encoding.TextUnmarshaler
接口。
database/sql
由 driver.Valuer
实现返回的错误现在已包装,以便在 DB.Query
、DB.Exec
和 DB.QueryRow
等操作期间改进错误处理。
debug/elf
debug/elf
包现在定义了 PT_OPENBSD_NOBTCFI
。此 ProgType
用于禁用 OpenBSD 二进制文件上的分支跟踪控制流完整性 (BTCFI) 强制执行。
现在定义了符号类型常量 STT_RELC
、STT_SRELC
和 STT_GNU_IFUNC
。
encoding/binary
新的 Encode
和 Decode
函数是 Read
和 Write
的字节切片等价物。Append
允许将多个数据编组到同一个字节切片中。
go/ast
新的 Preorder
函数返回一个方便的迭代器,用于遍历语法树的所有节点。
go/types
Func
类型(表示函数或方法符号)现在具有 Func.Signature
方法,该方法返回函数的类型,该类型始终为 Signature
。
Alias
类型现在具有 Rhs
方法,该方法返回其声明右侧的类型:给定 type A = B
,A 的 Rhs
是 B。(#66559)
已添加方法 Alias.Origin
、Alias.SetTypeParams
、Alias.TypeParams
和 Alias.TypeArgs
。它们是泛型别名类型所必需的。
默认情况下,go/types 现在为类型别名生成 Alias
类型节点。此行为可以通过 GODEBUG
gotypesalias
标志控制。其默认值已从 Go 1.22 中的 0 更改为 Go 1.23 中的 1。
math/rand/v2
已添加 Uint
函数和 Rand.Uint
方法。它们在 Go 1.22 中被无意中遗漏了。
新的 ChaCha8.Read
方法实现了 io.Reader
接口。
net
新的类型 KeepAliveConfig
允许通过新的 TCPConn.SetKeepAliveConfig
方法和 Dialer
和 ListenConfig
的新 KeepAliveConfig 字段,对 TCP 连接的保持活动选项进行微调。
DNSError
类型现在包装由超时或取消引起的错误。例如,errors.Is(someDNSErr, context.DeadlineExceedeed)
现在将报告 DNS 错误是否由超时引起。
新的 GODEBUG
设置 netedns0=0
禁用在 DNS 请求上发送 EDNS0 附加标头,因为据报道它们会破坏某些调制解调器上的 DNS 服务器。
net/http
Cookie
现在保留围绕 cookie 值的双引号。新的 Cookie.Quoted
字段指示 Cookie.Value
是否最初被引用。
新的 Request.CookiesNamed
方法检索与给定名称匹配的所有 cookie。
新的 Cookie.Partitioned
字段标识具有 Partitioned 属性的 cookie。
ServeMux
使用的模式现在允许在方法名称后使用一个或多个空格或制表符。以前,只允许一个空格。
新的 ParseCookie
函数解析 Cookie 标头值并返回其中设置的所有 cookie。由于同一个 cookie 名称可以出现多次,因此返回的值可以包含给定键的多个值。
新的 ParseSetCookie
函数解析 Set-Cookie 标头值并返回一个 cookie。它在语法错误时返回错误。
ServeContent
、ServeFile
和 ServeFileFS
现在在提供错误时删除 Cache-Control
、Content-Encoding
、Etag
和 Last-Modified
标头。这些标头通常适用于非错误内容,但不适用于错误文本。
包装 ResponseWriter
并应用即时编码(例如 Content-Encoding: gzip
)的中间件在此更改后将无法正常工作。ServeContent
、ServeFile
和 ServeFileFS
的先前行为可以通过设置 GODEBUG=httpservecontentkeepheaders=1
来恢复。
请注意,当 ServeContent
处理 Range 请求时,更改提供内容大小(例如通过压缩)的中间件已无法正常工作。即时压缩应使用 Transfer-Encoding
标头而不是 Content-Encoding
。
对于入站请求,新的 Request.Pattern
字段包含与请求匹配的 ServeMux
模式(如果有)。当设置 GODEBUG=httpmuxgo121=1
时,不会设置此字段。
net/http/httptest
新的 NewRequestWithContext
方法使用 context.Context
创建传入请求。
net/netip
在 Go 1.22 及更早版本中,使用 reflect.DeepEqual
比较包含 IPv4 地址的 Addr
与包含该地址的 IPv4 映射 IPv6 形式的 Addr
时,会错误地返回 true,即使使用 ==
或 Addr.Compare
比较时,Addr
值不同。此错误现已修复,所有三种方法现在都报告相同的结果。
os
Stat
函数现在为 Windows 上的 Unix 套接字文件设置 ModeSocket
位。这些文件通过将重新分析标记设置为 IO_REPARSE_TAG_AF_UNIX
来识别。
在 Windows 上,Lstat
和 Stat
报告的重新分析点的模式位已更改。挂载点不再设置 ModeSymlink
,并且不是符号链接、Unix 套接字或重复数据删除文件的重新分析点现在始终设置 ModeIrregular
。此行为由 winsymlink
设置控制。对于 Go 1.23,它默认为 winsymlink=1
。先前版本默认为 winsymlink=0
。
CopyFS
函数将 io/fs.FS
复制到本地文件系统。
在 Windows 上,Readlink
不再尝试将卷规范化为驱动器号,这并非总是可能的。此行为由 winreadlinkvolume
设置控制。对于 Go 1.23,它默认为 winreadlinkvolume=1
。先前版本默认为 winreadlinkvolume=0
。
在具有 pidfd 支持的 Linux 上(通常是 Linux v5.4 及更高版本),Process
相关的函数和方法在内部使用 pidfd(而不是 PID),消除了操作系统重用 PID 时可能发生的错误目标问题。Pidfd 支持对用户完全透明,除了进程可能具有的其他进程文件描述符。
path/filepath
新的 Localize
函数安全地将斜杠分隔路径转换为操作系统路径。
在 Windows 上,EvalSymlinks
不再评估挂载点,这是许多不一致和错误的来源。此行为由 winsymlink
设置控制。对于 Go 1.23,它默认为 winsymlink=1
。先前版本默认为 winsymlink=0
。
在 Windows 上,EvalSymlinks
不再尝试将卷规范化为驱动器号,这并非总是可能的。此行为由 winreadlinkvolume
设置控制。对于 Go 1.23,它默认为 winreadlinkvolume=1
。先前版本默认为 winreadlinkvolume=0
。
reflect
在 Type
中添加了与 Value
中同名方法同义的新方法。
Value.Pointer
和 Value.UnsafePointer
方法现在支持 kind 为 String
的值。
新的方法 Value.Seq
和 Value.Seq2
返回序列,这些序列迭代值,就像在 for/range 循环中使用一样。新的方法 Type.CanSeq
和 Type.CanSeq2
报告是否分别调用 Value.Seq
和 Value.Seq2
将在不出现恐慌的情况下成功。
runtime/debug
SetCrashOutput
函数允许用户指定运行时应将其致命崩溃报告写入的备用文件。它可用于构建所有意外崩溃的自动化报告机制,而不仅仅是那些在明确使用 recover
的 goroutine 中发生的崩溃。
runtime/pprof
alloc
、mutex
、block
、threadcreate
和 goroutine
配置文件的最大堆栈深度已从 32 帧提高到 128 帧。
runtime/trace
运行时现在在程序因未捕获的 panic 而崩溃时显式刷新跟踪数据。这意味着如果程序在跟踪处于活动状态时崩溃,则跟踪中将提供更完整的跟踪数据。
slices
Repeat
函数返回一个新的切片,该切片将提供的切片重复指定的次数。
sync
Map.Clear
方法删除所有条目,从而导致 Map
为空。它类似于 clear
。
sync/atomic
新的 And
和 Or
运算符对给定的输入应用按位 AND
或 OR
,并返回旧值。
syscall
syscall 包现在在 Windows 上定义了 WSAENOPROTOOPT
。
GetsockoptInt
函数现在在 Windows 上受支持。
testing/fstest
TestFS
现在返回一个结构化错误,该错误可以解包(通过方法 Unwrap() []error
)。这允许使用 errors.Is
或 errors.As
检查错误。
text/template
模板现在支持新的“else with”操作,这在某些用例中减少了模板的复杂性。
time
Parse
和 ParseInLocation
现在在时区偏移量超出范围时返回错误。
在 Windows 上,Timer
、Ticker
和使 goroutine 休眠的函数(例如 Sleep
)的时间分辨率已提高到 0.5 毫秒,而不是 15.6 毫秒。
unicode/utf16
RuneLen
函数返回 rune 的 UTF-16 编码中 16 位字的数量。如果 rune 不是 UTF-16 中有效的编码值,则返回 -1。
端口
Darwin
如 Go 1.22 发行说明中 宣布 的,Go 1.23 需要 macOS 11 Big Sur 或更高版本;对先前版本的支持已停止。
Linux
Go 1.23 是最后一个需要 Linux 内核版本 2.6.32 或更高版本的版本。Go 1.24 将需要 Linux 内核版本 3.2 或更高版本。
OpenBSD
Go 1.23 为 64 位 RISC-V 上的 OpenBSD 添加了实验性支持(GOOS=openbsd
,GOARCH=riscv64
)。
ARM64
Go 1.23 引入了新的 GOARM64
环境变量,该变量在编译时指定 ARM64 架构的最低目标版本。允许的值为 v8.{0-9}
和 v9.{0-5}
。后面可以跟一个选项,指定目标硬件实现的扩展。有效选项为 ,lse
和 ,crypto
。
GOARM64
环境变量默认为 v8.0
。
RISC-V
Go 1.23 引入了新的 GORISCV64
环境变量,用于选择要编译的 RISC-V 用户模式应用程序配置文件。允许的值为 rva20u64
和 rva22u64
。
GORISCV64
环境变量默认为 rva20u64
。
Wasm
GOROOT/misc/wasm
中的 go_wasip1_wasm_exec
脚本已放弃对 wasmtime
< 14.0.0 版本的支持。