go新版本发布:iter迭代器、修复遗留近10年bug

215 阅读12分钟

Go 1.23 发布说明

Go 1.23 简介

Go 1.23 是 Go 语言的最新发布版本,距离 Go 1.22 发布已经过去了六个月。此版本带来了多项语言变更、工具改进以及标准库的更新。

语言变更

范围迭代器

Go 1.23 将 Go 1.22 中的 range-over-func 实验性功能正式纳入语言规范。在 for-range 循环中,range 子句现在接受以下类型的迭代器函数作为范围表达式:

func(func() boolfunc(func(K) boolfunc(func(K, V) bool)

这些迭代器函数的调用将产生迭代值。

泛型类型别名预览支持

Go 1.23 提供了对泛型类型别名的预览支持。通过在构建工具链时设置 GOEXPERIMENT=aliastypeparams,可以在包内启用此功能。跨包边界使用泛型别名类型尚不支持。

工具

Telemetry

从 Go 1.23 开始,Go 工具链可以收集使用情况和中断统计信息,以帮助 Go 团队了解 Go 的使用情况。Telemetry 是一个可选系统,通过 go telemetry 命令控制。默认情况下,工具链程序将统计信息收集到本地计数器文件中,但不会上传。若要选择加入 Telemetry,请运行 go telemetry on。在该模式下,匿名计数器报告将每周上传到 telemetry.go.dev,并聚合成图表供 Go 贡献者或用户分析。

Go 命令

  • • 设置 GOROOT_FINAL 环境变量不再生效(#62047)。
  • • go env -changed 标志仅打印那些有效值与默认值不同的设置。
  • • go mod tidy -diff 标志不修改文件,而是将必要的更改以统一差异格式打印出来。
  • • go list -m -json 命令现在包括新的 Sum 和 GoModSum 字段。
  • • 新的 godebug 指令。

Vet

  • • stdversion analyzergo vet 子命令现在包括 stdversion analyzer,该分析器会标记对当前生效 Go 版本中太新的符号的引用。有效版本由文件所在模块的 go.mod 文件中的 go 指令以及文件中的任何 //go:build 约束决定。

Cgo

  • • -ldflags 标志cmd/cgo 支持新的 -ldflags 标志,用于向 C 链接器传递标志。go 命令会自动使用此标志,避免 CGO_LDFLAGS 非常大时导致的“参数列表过长”错误。

Trace

  • • 更健壮的跟踪数据恢复: 跟踪工具现在更好地容忍部分损坏的跟踪数据,尝试恢复可恢复的数据。这在查看程序崩溃期间收集的跟踪时特别有用,因为大多数情况下现在可以恢复崩溃之前的跟踪数据。

Runtime

  • • 错误消息缩进: 运行时在打印未处理的 panic 或其他致命错误后,现在会将错误消息的第二行及后续行缩进一个制表符,以便与第一个 goroutine 的堆栈跟踪明确区分。

Compiler

  • • PGO 构建时间开销减少: 使用 Profile Guided Optimization (PGO) 构建时的开销已显著降低。在 Go 1.23 中,开销应保持在个位数百分比。
  • • 局部变量重叠优化: Go 1.23 编译器现在可以重叠在函数不相交区域中访问的局部变量堆栈帧槽位,从而减少 Go 应用程序的堆栈使用。
  • • 热点块对齐: 对于 386 和 amd64,编译器将使用 PGO 信息来对齐循环中的某些热点块,这将以额外的 0.1% 文本和二进制大小为代价,提高 1-1.5% 的性能。

Linker

  • • 内部符号引用限制: 链接器现在不允许使用 //go:linkname 指令来引用标准库(包括运行时)中未在其定义上标记为 //go:linkname 的内部符号。同样,链接器也不允许从汇编代码中引用此类符号。
  • • -bindnow 标志: 构建动态链接的 ELF 二进制文件(包括 PIE 二进制文件)时,新的 -bindnow 标志启用即时函数绑定。

标准库

Timer changes

  • • 垃圾收集改进: 不再被程序引用的 Timer 和 Ticker 会立即成为垃圾收集的目标,即使它们的 Stop 方法未被调用。
  • • 无缓冲通道: Timer 或 Ticker 关联的通道现在是无缓冲的,容量为 0。

New unique package

  • • 值规范化: 提供了用于规范化值(如“interning”或“hash-consing”)的设施。

Iterators

  • • iter 包: 提供了用户定义迭代器的基本定义。
  • • slices 和 maps 包: 添加了多个与迭代器一起工作的函数。

New structs package

  • • HostLayout 类型: 指示具有该类型字段的结构具有符合主机平台期望的布局。

Minor changes to the library

archive/tar

  • • 如果 FileInfoHeader 的参数实现了新的 FileInfoNames 接口,则该接口的方法将用于设置文件头的 Uname/Gname。这允许应用程序覆盖系统依赖的 Uname/Gname 查找。

crypto/tls

  • • TLS 客户端现在支持 Encrypted Client Hello 草案规范。可以通过设置 Config.EncryptedClientHelloConfigList 字段为编码的 ECHConfigList 来启用此功能。
  • • QUICConn 类型现在包括新的事件报告会话恢复的状态,并提供了一种方式为 QUIC 层向会话票据和会话缓存条目添加数据。
  • • 从默认列表中移除了 3DES 密码套件(当 Config.CipherSuites 为 nil 时)。可以通过将 tls3des=1 添加到 GODEBUG 环境变量来恢复默认设置。
  • • 实验性的后量子密钥交换机制 X25519Kyber768Draft00 在 Config.CurvePreferences 为 nil 时默认启用。可以通过将 tlskyber=0 添加到 GODEBUG 环境变量来恢复默认设置。
  • • Go 1.23 更改了 X509KeyPair 和 LoadX509KeyPair 的行为,以填充返回的 Certificate.Leaf 字段。添加了新的 x509keypairleaf GODEBUG 设置来控制此行为。

crypto/x509

  • • CreateCertificateRequest 现在正确支持 RSA-PSS 签名算法。
  • • CreateCertificateRequest 和 CreateRevocationList 现在使用签名者的公钥验证生成的签名。如果签名无效,将返回错误。
  • • x509sha1 GODEBUG 设置将在下一个 Go 主要版本(Go 1.24)中被移除,届时 crypto/x509 将不再支持验证使用 SHA-1 签名算法的证书上的签名。
  • • 添加了新的 ParseOID 函数来解析点编码的 ASN.1 对象标识符字符串。

database/sql

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

debug/elf

  • • 定义了 PT_OPENBSD_NOBTCFI,用于在 OpenBSD 二进制文件上禁用分支跟踪控制流完整性(BTCFI)执行。
  • • 定义了符号类型常量 STT_RELCSTT_SRELC 和 STT_GNU_IFUNC

encoding/binary

  • • 添加了新的 Encode 和 Decode 函数,它们是 Read 和 Write 的字节切片等效项。Append 允许将多个数据编组到同一个字节切片中。

go/ast

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

go/types

  • • Func 类型现在有一个 Func.Signature 方法,该方法返回函数的类型,它总是一个 Signature
  • • Alias 类型现在有一个 Rhs 方法,返回其声明右侧的类型。
  • • 添加了 Alias.OriginAlias.SetTypeParamsAlias.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 类型允许对 TCP 连接的保持活动选项进行微调。
  • • DNSError 类型现在包装由超时或取消引起的错误。
  • • 新的 GODEBUG 设置 netedns0=0 禁用在 DNS 请求上发送 EDNS0 附加头。

net/http

  • • Cookie 现在会保留围绕 cookie 值的双引号。新的 Cookie.Quoted 字段指示 Cookie.Value 是否原本被引号包围。
  • • 新的 Request.CookiesNamed 方法检索所有与给定名称匹配的 cookie。
  • • 新的 Cookie.Partitioned 字段标识具有 Partitioned 属性的 cookie。
  • • ServeMux 使用的模式现在允许在方法名后有一个或多个空格或制表符。之前只允许单个空格。
  • • 新的 ParseCookie 函数解析 Cookie 头值,并返回其中设置的所有 cookie。由于相同的 cookie 名称可以出现多次,因此返回的 Values 可以包含给定键的多个值。
  • • 新的 ParseSetCookie 函数解析 Set-Cookie 头值并返回一个 cookie。在语法错误时返回错误。
  • • ServeContentServeFile 和 ServeFileFS 在服务错误时现在会移除 Cache-ControlContent-EncodingEtag 和 Last-Modified 头。这些头通常适用于非错误内容,而不适用于错误文本。
  • • 包裹 ResponseWriter 并应用即时编码的中间件(如 Content-Encoding: gzip)在此更改后将无法正常工作。可以通过设置 GODEBUG=httpservecontentkeepheaders=1 来恢复 ServeContentServeFile 和 ServeFileFS 的先前行为。
  • • 对于入站请求,新的 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 报告的 reparse 点的模式位已更改。挂载点不再具有 ModeSymlink 设置,且不是符号链接、Unix 套接字或重复数据删除文件的 reparse 点现在始终具有 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+),与进程相关的函数和方法内部使用 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 中同名方法相对应的新方法:
    • • Type.OverflowComplex
    • • Type.OverflowFloat
    • • Type.OverflowInt
    • • Type.OverflowUint
  • • 新增了 SliceAt 函数,其功能类似于 NewAt,但适用于切片。
  • • Value.Pointer 和 Value.UnsafePointer 方法现在支持 String 类型的值。
  • • 新增了 Value.Seq 和 Value.Seq2 方法,它们返回序列,这些序列遍历值的方式就像在 for/range 循环中使用该值一样。
  • • 新增了 Type.CanSeq 和 Type.CanSeq2 方法,它们分别报告调用 Value.Seq 和 Value.Seq2 是否会成功而不会引发 panic。

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

  • • 在 Windows 上,syscall 包现在定义了 WSAENOPROTOOPT
  • • GetsockoptInt 函数现在在 Windows 上受支持。

testing/fstest

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

text/template

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

time

  • • 如果时区偏移量超出范围,Parse 和 ParseInLocation 现在将返回错误。

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.17 或更高版本,但有一个例外:如果内核已打补丁以支持 getrandom 系统调用,则运行 3.10 或更高版本的系统将继续受支持。

OpenBSD

  • • Go 1.23 为 OpenBSD 在 64 位 RISC-V 上添加了实验性支持(GOOS=openbsdGOARCH=riscv64)。

ARM64

  • • Go 1.23 引入了新的 GOARM64 环境变量,该变量在编译时指定 ARM64 架构的最小目标版本。允许的值是 v8.{0-9} 和 v9.{0-5}。这后面可以跟一个选项,指定目标硬件实现的扩展。有效选项是 ,lse 和 ,cryptoGOARM64 环境变量的默认值是 v8.0

RISC-V

  • • Go 1.23 引入了新的 GORISCV64 环境变量,该变量选择为哪个 RISC-V 用户模式应用程序配置文件进行编译。允许的值是 rva20u64 和 rva22u64GORISCV64 环境变量的默认值是 rva20u64

Wasm

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

参考文档