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 命令现在包含新的 SumGoModSum 字段。这类似于 go mod download -json 命令的现有行为。

go.modgo.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.Timertime.Ticker 的实现进行了两次重大更改。

首先,程序不再引用的 TimerTicker 立即有资格进行垃圾回收,即使尚未调用其 Stop 方法。早期版本的 Go 不会在 Timer 触发后才回收未停止的 Timer,并且从不回收未停止的 Ticker

其次,与 TimerTicker 关联的计时器通道现在是无缓冲的,容量为 0。此更改的主要影响是 Go 现在保证对于对 ResetStop 方法的任何调用,在该调用之前准备的任何陈旧值都不会在调用后发送或接收。早期版本的 Go 使用具有一个元素缓冲区的通道,这使得难以正确使用 ResetStop。此更改的一个可见效果是,计时器通道的 lencap 现在返回 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 包添加了一些与迭代器一起使用的函数。

新的 maps 包添加了一些与迭代器一起使用的函数。

新的 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 更改了 X509KeyPairLoadX509KeyPair 的行为,以填充返回的 CertificateCertificate.Leaf 字段。为该行为添加了新的 x509keypairleaf GODEBUG 设置

crypto/x509

CreateCertificateRequest 现在正确支持 RSA-PSS 签名算法。

CreateCertificateRequestCreateRevocationList 现在使用签名者的公钥验证生成的签名。如果签名无效,则返回错误。自 Go 1.16 以来,这已成为 CreateCertificate 的行为。

x509sha1 GODEBUG 设置 将在下一个 Go 主版本(Go 1.24)中删除。这意味着 crypto/x509 将不再支持验证使用基于 SHA-1 的签名算法的证书上的签名。

新的 ParseOID 函数解析点编码的 ASN.1 对象标识符字符串。OID 类型现在实现了 encoding.BinaryMarshalerencoding.BinaryUnmarshalerencoding.TextMarshalerencoding.TextUnmarshaler 接口。

database/sql

driver.Valuer 实现返回的错误现在已包装,以便在 DB.QueryDB.ExecDB.QueryRow 等操作期间改进错误处理。

debug/elf

debug/elf 包现在定义了 PT_OPENBSD_NOBTCFI。此 ProgType 用于禁用 OpenBSD 二进制文件上的分支跟踪控制流完整性 (BTCFI) 强制执行。

现在定义了符号类型常量 STT_RELCSTT_SRELCSTT_GNU_IFUNC

encoding/binary

新的 EncodeDecode 函数是 ReadWrite 的字节切片等价物。Append 允许将多个数据编组到同一个字节切片中。

go/ast

新的 Preorder 函数返回一个方便的迭代器,用于遍历语法树的所有节点。

go/types

Func 类型(表示函数或方法符号)现在具有 Func.Signature 方法,该方法返回函数的类型,该类型始终为 Signature

Alias 类型现在具有 Rhs 方法,该方法返回其声明右侧的类型:给定 type A = B,A 的 Rhs 是 B。(#66559

已添加方法 Alias.OriginAlias.SetTypeParamsAlias.TypeParamsAlias.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 方法和 DialerListenConfig 的新 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。它在语法错误时返回错误。

ServeContentServeFileServeFileFS 现在在提供错误时删除 Cache-ControlContent-EncodingEtagLast-Modified 标头。这些标头通常适用于非错误内容,但不适用于错误文本。

包装 ResponseWriter 并应用即时编码(例如 Content-Encoding: gzip)的中间件在此更改后将无法正常工作。ServeContentServeFileServeFileFS 的先前行为可以通过设置 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 上,LstatStat 报告的重新分析点的模式位已更改。挂载点不再设置 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 中同名方法同义的新方法。

  1. Type.OverflowComplex
  2. Type.OverflowFloat
  3. Type.OverflowInt
  4. Type.OverflowUint

新的 SliceAt 函数类似于 NewAt,但用于切片。

Value.PointerValue.UnsafePointer 方法现在支持 kind 为 String 的值。

新的方法 Value.SeqValue.Seq2 返回序列,这些序列迭代值,就像在 for/range 循环中使用一样。新的方法 Type.CanSeqType.CanSeq2 报告是否分别调用 Value.SeqValue.Seq2 将在不出现恐慌的情况下成功。

runtime/debug

SetCrashOutput 函数允许用户指定运行时应将其致命崩溃报告写入的备用文件。它可用于构建所有意外崩溃的自动化报告机制,而不仅仅是那些在明确使用 recover 的 goroutine 中发生的崩溃。

runtime/pprof

allocmutexblockthreadcreategoroutine 配置文件的最大堆栈深度已从 32 帧提高到 128 帧。

runtime/trace

运行时现在在程序因未捕获的 panic 而崩溃时显式刷新跟踪数据。这意味着如果程序在跟踪处于活动状态时崩溃,则跟踪中将提供更完整的跟踪数据。

slices

Repeat 函数返回一个新的切片,该切片将提供的切片重复指定的次数。

sync

Map.Clear 方法删除所有条目,从而导致 Map 为空。它类似于 clear

sync/atomic

新的 AndOr 运算符对给定的输入应用按位 ANDOR,并返回旧值。

syscall

syscall 包现在在 Windows 上定义了 WSAENOPROTOOPT

GetsockoptInt 函数现在在 Windows 上受支持。

testing/fstest

TestFS 现在返回一个结构化错误,该错误可以解包(通过方法 Unwrap() []error)。这允许使用 errors.Iserrors.As 检查错误。

text/template

模板现在支持新的“else with”操作,这在某些用例中减少了模板的复杂性。

time

ParseParseInLocation 现在在时区偏移量超出范围时返回错误。

在 Windows 上,TimerTicker 和使 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=openbsdGOARCH=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 用户模式应用程序配置文件。允许的值为 rva20u64rva22u64

GORISCV64 环境变量默认为 rva20u64

Wasm

GOROOT/misc/wasm 中的 go_wasip1_wasm_exec 脚本已放弃对 wasmtime < 14.0.0 版本的支持。