Read Buf

Read Buf

Go 1.23 RC2 版本发布

language

Golang 团队刚刚发布了 Go 1.23rc2,这是 Go 1.23 的候选发布版本。

这个版本是从 release-branch.go1.23 分支中切割并打上 go1.23rc2 标签的。

如果你已经安装了 Go,可以通过以下 go 命令尝试 go1.23rc2:

$ go install golang.org/dl/go1.23rc2@latest
$ go1.23rc2 download

pic

Go 1.23 还未发布。这些内容是草稿发布说明。Go 1.23 预计将在 2024 年 8 月发布。

语言变化

Go 1.23 将 (Go 1.22) “range-over-func” 试验纳入语言的一部分。现在,“for-range” 循环中的 “range” 子句可以接受以下类型的迭代器函数

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

范围表达式。调用迭代器参数函数可以生成“for-range”循环的迭代值。详细信息请参阅iter包文档和语言规范。有关动机,请参考2022年的 “range-over-func” 讨论。

Go 1.23 增加了对泛型类型别名的预览支持,使用GOEXPERIMENT=aliastypeparams构建工具链可以启用这个功能。

工具

遥测

从 Go 1.23 开始,Go 工具链支持收集工具使用情况和故障统计信息,帮助 Go 团队更好地了解工具链的使用情况和性能。我们称这些统计信息为 Go 遥测。

Go 遥测是一个可以选择加入的系统,由 go telemetry 命令进行控制。默认情况下,工具链程序会将统计信息收集到本地的计数文件中,但不会进行其他用途(通过go telemetry local命令查看)。

为了帮助我们改进 Go 工具链并更好地了解其使用情况,请考虑运行go telemetry on命令选择加入 Go 遥测模式。在该模式下,匿名的统计报告会每周上传到telemetry.go.dev,这些报告将被汇总为图表,供任何希望分析数据的 Go 贡献者和用户下载。更多细节请参阅[Go Telemetry]文档。

Go 命令

设置 GOROOT_FINAL 环境变量现在已经无效。如果发行版将 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 约束 确定。

例如,当一个文件使用 reflect.TypeFor 函数(在 go1.22 中引入),而该文件所属模块的 go.mod 文件指定的是 go 1.21 时,它将会报告一个诊断。

Cgo

cmd/cgo 现在支持新的 -ldflags 标志,用于传递参数给 C 链接器。go 命令会自动使用这个标志,从而避免在使用非常大的 CGO_LDFLAGS 时出现“参数列表过长”的错误。

Trace

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

Runtime

在未处理的 panic 或其他致命错误后,由运行时打印的回溯信息中,错误消息的第二行及后续行(例如 panic 参数)现在会缩进一个制表符,以便能够明确区分第一协程的堆栈回溯。

Compiler

启用 Profile Guided Optimization 的构建时间开销已显著减少。以前,在启用 PGO 后,大型构建的时间可能会增加 100% 以上。而在 Go 1.23 中,开销应控制在个位数百分比。

Go 1.23 的编译器现在可以在函数不同区域中访问的局部变量使用相同的栈帧槽,从而减少了 Go 应用的栈空间使用。

对于 386 和 amd64,编译器将利用来自 PGO (Profile-Guided Optimization) 的信息来对循环中的某些高频块进行对齐优化。虽然这会额外增加 0.1% 的文本和二进制文件大小,但能进一步提升 1-1.5% 的性能。目前这项优化仅在 386 和 amd64 平台上实现,因为在其他平台上未见显著提升。可以使用 -gcflags=[<packages>=]-d=alignhot=0 禁用这项优化。

链接器

链接器现在禁止使用 //go:linkname 指令引用标准库(包括运行时)中未标记 //go:linkname 的内部符号。同样,从汇编代码中引用这些符号也被禁止。为了保持向后兼容,现存于大型开源代码库中的 //go:linkname 用法仍被支持,但新的引用将被禁止。

为了调试和实验用途,可以使用链接器命令行标志 -checklinkname=0 禁用此检查。

在构建动态链接的 ELF (包括 PIE) 二进制文件时,新的 -bindnow 标志可以启用立即函数绑定。

标准库

Timer 更改

Go 1.23 对 time.Timertime.Ticker 实现了两项重要的改动。

首先,即使没有调用 Stop 方法,当程序不再引用 TimerTicker 时,它们会立即成为垃圾回收的对象。而在早期版本的 Go 中,未停止的 Timer 只有在触发之后才会被回收,并且未停止的 Ticker 是永远不会被回收的。

其次,现在与 TimerTicker 关联的计时器通道变成了无缓冲通道,容量为 0。这意味着在调用 ResetStop 方法时,Go 可以保证在该调用之前准备的任何陈旧值都不会在调用之后被发送或接收。早期版本的 Go 使用的是单元素缓冲通道,这使得正确使用 ResetStop 变得困难。一个明显的变化是计时器通道的 lencap 现在返回 0 而不是 1,这可能会影响那些依赖通道长度来决定接收操作是否可以成功的程序。此类代码应改为使用非阻塞接收。

这些新行为只有在主要 Go 程序的 go.mod 文件中使用 Go 1.23.0 或更高版本时才会启用。当 Go 1.23 构建旧程序时,旧行为仍然有效。通过新的 GODEBUG 设置 asynctimerchan=1,即使在程序的 go.mod 文件中指定了 Go 1.23.0 或更高版本,也可以恢复到异步通道行为。

新 unique 包

新的 unique 包提供了值的标准化功能(例如“驻留 (interning)”或“散列表驻留 (hash-consing)”)。

任何可比较类型的值都可以使用新的 Make[T] 函数进行标准化。这个函数会生成一个指向该值的标准副本的引用,即 Handle[T]。只有当生成句柄的值相等时,两个 Handle[T] 才相等,而这种方式使得程序能够去重值并减少内存占用。比较两个 Handle[T] 的效率很高,因为只需要简单的指针比较。

迭代器

新的 iter 包定义了使用用户定义迭代器的基础。

slices 包增加了多个与迭代器相关的函数:

  • All 返回一个迭代切片索引和值的迭代器。
  • Values 返回一个迭代切片元素的迭代器。
  • Backward 返回一个反向迭代切片的迭代器。
  • Collect 将迭代器中的值收集到一个新的切片中。
  • AppendSeq 将迭代器中的值追加到现有的切片。
  • Sorted 将迭代器中的值收集到一个新的切片中,并对切片排序。
  • SortedFunc 类似于 Sorted,但可以自定义比较函数。
  • SortedStableFunc 类似于 SortedFunc,但使用稳定排序算法。
  • Chunk 返回一个迭代器,可以遍历一个切片中最多 n 个元素的连续子切片。

maps 包增加了几个操作迭代器的新函数:

  • All 返回一个遍历映射中键值对的迭代器。
  • Keys 返回一个遍历映射中所有键的迭代器。
  • Values 返回一个遍历映射中所有值的迭代器。
  • Insert 将迭代器中的键值对添加到现有的映射中。
  • Collect 将迭代器中的键值对收集到一个新的映射并返回它。

新的 structs 包

全新的 structs 包提供了一些用于结构体字段的类型,这些类型可以修改包含它们的结构体的某些属性,比如内存布局。

在这个版本中,唯一提供的类型是 HostLayout,它表明包含该字段的结构体的布局符合主机平台的标准。

库的其他小改动

archive/tar

如果传给 FileInfoHeader 的参数实现了新的 FileInfoNames 接口,那么接口方法将用于设置文件头部的 Uname/Gname。这样应用程序可以覆写系统默认的 Uname/Gname 查找方式。

crypto/tls

TLS 客户端现在支持加密的客户端 Hello (Encrypted Client Hello) 草案规范。启用此功能的方法是设置 Config.EncryptedClientHelloConfigList字段为要连接主机的 ECHConfigList 编码。

QUIC 实现中的 QUICConn 类型现在包含新的事件,用于报告会话恢复状态,并提供了让 QUIC 层向会话票证和缓存条目添加数据的方法。

3DES 密码套件已从默认列表中移除(当 Config.CipherSuites 为 nil 时)。可以通过在 GODEBUG 环境变量中添加 tls3des=1 来恢复默认设置。

Config.CurvePreferences 为 nil 时,实验性的后量子密钥交换机制 X25519Kyber768Draft00 现在会被默认启用。可以通过在 GODEBUG 环境变量中添加 tlskyber=0 来恢复之前的设置。

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.Query, DB.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 类型节点。这个行为可以通过使用 GODEBUGgotypesalias 标志进行控制。其默认值已从 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.DeadlineExceeded) 现在会报告 DNS 错误是否由超时引起。

新的 GODEBUG 设置 netedns0=0 取消了 DNS 请求中发送 EDNS0 附加报头的功能,因为这些报头会导致某些调制解调器的 DNS 服务器工作异常。

net/http

Cookie 现在会保留包围 cookie 值的双引号。新的字段 Cookie.Quoted 用来表示 Cookie.Value 是否最初包含引号。

新的方法 Request.CookiesNamed 可以检索出所有与给定名称匹配的 cookies。

新的字段 Cookie.Partitioned 用来识别具有 Partitioned 属性的 cookies。

ServeMux 现在支持方法名称后面可以有一个或多个空格或制表符,而以前只允许一个空格。

新的函数 ParseCookie 可以解析 Cookie 头值并返回其中设置的所有 cookies。由于同名的 cookie 可以出现多次,返回值中可能包含同一个键的多个值。

新的函数 ParseSetCookie 可以解析 Set-Cookie 头值并返回一个 cookie。如果遇到语法错误,该函数将返回错误信息。

ServeContentServeFileServeFileFS 在返回错误信息时,会移除 Cache-ControlContent-EncodingEtagLast-Modified 头。这些头通常适用于非错误内容,而不适用于错误信息。

封装 ResponseWriter 并应用实时编码(例如 Content-Encoding: gzip)的中间件,在此更改后将不再生效。可以通过设置 GODEBUG=httpservecontentkeepheaders=1 来恢复 ServeContentServeFileServeFileFS 的之前行为。

需要注意的是,当 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 值在使用 ==Addr.Compare 比较时不同,却会错误地返回 true。这个错误现在已经修复,三种方法现在都会报告相同的比较结果。

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

path/filepath

新的 Localize 函数可以安全地将斜杠分隔的路径转换为操作系统路径。

在 Windows 上,EvalSymlinks 不再评估装载点,这是许多不一致和错误的根源之一。这种行为由 winsymlink 设置控制。在 Go 1.23 中,默认设置为 winsymlink=1,而以前的版本默认设置为 winsymlink=0

在 Windows 上,EvalSymlinks 不再尝试将卷路径规范化为驱动器字母,因为这样做并不总是可行。这种行为由 winreadlinkvolume 设置控制。在 Go 1.23 中,默认设置为 winreadlinkvolume=1,而以前的版本默认设置为 winreadlinkvolume=0

reflect

Value 方法同名的新方法已被添加到 Type 中:

  1. Type.OverflowComplex

  2. Type.OverflowFloat

  3. Type.OverflowInt

  4. Type.OverflowUint

新的 SliceAt 函数功能类似于 NewAt,但专用于切片 (slice) 。

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

新增加的 Value.SeqValue.Seq2 方法返回一个序列,可以像在 for/range 循环中使用值那样进行迭代。而新的 Type.CanSeqType.CanSeq2 方法则可以检查调用 Value.SeqValue.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

新增的 AndOr 操作符会对输入值执行按位 ANDOR 操作,并返回旧值。

syscall

syscall 包现在在 Windows 系统中定义了 WSAENOPROTOOPT

GetsockoptInt 函数现在支持在 Windows 上运行。

testing/fstest

TestFS 现在会返回一个可以展开的结构化错误(通过方法 Unwrap() []error)。这样便于使用 errors.Iserrors.As 检查错误。

text/template

模板现在支持新的 else with 操作,这在一些使用场景中可以降低模板的复杂性。

time

ParseParseInLocation 现在如果时区偏移量超出范围,则会返回错误。

unicode/utf16

RuneLen 函数返回 UTF-16 编码中 rune 的 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 或更高,但如果运行的是 3.10 或更高且内核已支持 getrandom 系统调用的系统,仍将继续支持。

OpenBSD

Go 1.23 增加了对 64 位 RISC-V (GOOS=openbsd, GOARCH=riscv64) 上 OpenBSD 的实验性支持。

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。