Go 1.20 发布说明

Go 1.20 简介

最新发布的 Go 1.20 版本距离 Go 1.19 发布已有六个月。其大部分变化都在工具链、运行时和标准库的实现中。一如既往,此版本保持了 Go 1 的兼容性承诺。我们预计几乎所有的 Go 程序都将像以前一样继续编译和运行。

语言方面的变化

Go 1.20 包含语言方面的四项变化。

Go 1.17 添加了从 slice 到数组指针的转换。Go 1.20 将其扩展到允许从 slice 到数组的转换:给定一个 slice x,现在可以直接写 [4]byte(x),而无需写 *(*[4]byte)(x)

The unsafe定义了三个新函数:SliceDataStringStringData。与 Go 1.17 的 Slice 函数一起,这些函数现在提供了构建和解构 slice 和字符串值的完整能力,而无需依赖于它们的具体内存表示。

规范现在定义了 struct 值按字段逐一比较,按照字段在 struct 类型定义中出现的顺序进行,并在第一个不匹配时停止。以前的规范可以被理解为即使在第一个不匹配后仍需要比较所有字段。类似地,规范现在定义了数组值按元素逐一比较,按递增索引顺序进行。在这两种情况下,这种差异影响了某些比较是否必须触发 panic。现有程序不受影响:新的规范措辞描述了实现一直以来的行为。

可比较类型(例如普通接口)现在可以满足 comparable 约束,即使类型参数不是严格可比较的(运行时比较可能触发 panic)。这使得使用非严格可比较的类型参数(例如接口类型,或包含接口类型的复合类型)来实例化受 comparable 约束的类型参数(例如用户定义的泛型 map key 的类型参数)成为可能。

移植

Windows

Go 1.20 是最后一个可在任意版本的 Windows 7、8、Server 2008 和 Server 2012 上运行的版本。Go 1.21 将至少需要 Windows 10 或 Server 2016。

Darwin 和 iOS

Go 1.20 是最后一个可在 macOS 10.13 High Sierra 或 10.14 Mojave 上运行的版本。Go 1.21 将至少需要 macOS 10.15 Catalina 或更高版本。

FreeBSD/RISC-V

Go 1.20 添加了对 RISC-V 平台上的 FreeBSD 的实验性支持 (GOOS=freebsd, GOARCH=riscv64)。

工具

Go 命令

目录 $GOROOT/pkg 不再存储标准库的预编译包归档:go install 不再写入它们,go build 不再检查它们,Go 发行版也不再附带它们。取而代之的是,标准库中的包会在需要时构建并缓存在构建缓存中,就像 GOROOT 之外的包一样。这项更改减小了 Go 发行版的大小,同时也避免了使用 cgo 的包的 C 工具链差异问题。

go test -json 的实现已得到改进,使其更加健壮。运行 go test -json 的程序无需进行任何更新。直接调用 go tool test2json 的程序现在应使用 -v=test2json 运行测试二进制文件(例如,go test -v=test2json./pkg.test -test.v=test2json),而不是简单的 -v

go test -json 相关的一项更改是,在每个测试程序执行开始时,添加了一个 Action 设置为 start 的事件。使用 go 命令运行多个测试时,这些 start 事件的发出顺序保证与命令行中指定的包名称顺序一致。

go 命令现在定义了架构特性构建标签(例如 amd64.v2),以允许根据特定架构特性的存在与否来选择包的实现文件。详细信息请参见go help buildconstraint

go 子命令现在接受 -C <dir> 参数,用于在执行命令前切换到指定目录 <dir>,这对于需要在多个不同模块中执行命令的脚本可能很有用。

go buildgo test 命令不再接受 -i 标志,该标志自 Go 1.16 起已被弃用

go generate 命令现在接受 -skip <pattern> 参数,用于跳过与指定模式 <pattern> 匹配的 //go:generate 指令。

go test 命令现在接受 -skip <pattern> 参数,用于跳过与指定模式 <pattern> 匹配的测试、子测试或示例。

当主模块位于 GOPATH/src 内时,go install 不再将非 main 包的库安装到 GOPATH/pkg,并且 go list 不再为此类包报告 Target 字段。(在模块模式下,编译后的包仅存储在构建缓存中,但是一个 bug 曾导致 GOPATH 安装目标意外地保持生效。)

go buildgo install 以及其他与构建相关的命令现在支持 -pgo 标志,该标志用于启用配置文件引导优化(profile-guided optimization),这将在下面的编译器部分详细描述。-pgo 标志指定配置文件的文件路径。指定 -pgo=auto 会使 go 命令在主包目录中搜索名为 default.pgo 的文件,如果存在则使用它。当前此模式要求在命令行中指定一个主包,但我们计划在未来的版本中取消此限制。指定 -pgo=off 会关闭配置文件引导优化。

go buildgo install 以及其他与构建相关的命令现在支持 -cover 标志,该标志用于构建带有代码覆盖率检测的目标。这将在下面的覆盖率部分详细描述。

go version

go version -m 命令现在支持读取更多类型的 Go 二进制文件,最显著的是使用 go build -buildmode=c-shared 构建的 Windows DLL 文件和没有执行权限的 Linux 二进制文件。

Cgo

在没有 C 工具链的系统上,go 命令现在默认禁用 cgo。更具体地说,当未设置 CGO_ENABLED 环境变量、未设置 CC 环境变量且路径中找不到默认的 C 编译器(通常是 clanggcc)时,CGO_ENABLED 默认为 0。像往常一样,您可以通过显式设置 CGO_ENABLED 来覆盖默认值。

这项默认更改最重要的影响是,当 Go 安装在没有 C 编译器的系统上时,它现在将对使用 cgo 的标准库包使用纯 Go 构建,而不再使用预发布的包归档(这些已被移除,如上文所述),或尝试使用 cgo 却失败。这使得 Go 在一些最小化的容器环境以及 macOS 上运行得更好,因为自 Go 1.16 以来,macOS 上基于 cgo 的包就未使用预发布的包归档了。

标准库中使用 cgo 的包是 netos/userplugin。在 macOS 上,netos/user 包已被重写,不再使用 cgo:现在 cgo 和非 cgo 构建以及交叉编译构建都使用相同的代码。在 Windows 上,netos/user 包从未 Cgo。在其他系统上,禁用 cgo 的构建将使用这些包的纯 Go 版本。

因此,在 macOS 上,如果使用 net 包的 Go 代码是使用 -buildmode=c-archive 构建的,则在链接 C 代码时,将生成的归档文件链接到 C 程序需要传递 -lresolv

在 macOS 上,竞态检测器已被重写,不再使用 cgo:启用竞态检测器的程序无需 Xcode 即可构建和运行。在 Linux 和其他 Unix 系统以及 Windows 上,使用竞态检测器需要宿主 C 工具链。

覆盖率

Go 1.20 支持为程序(应用程序和集成测试)收集代码覆盖率配置文件,而不仅仅是单元测试。

要为程序收集覆盖率数据,请使用 go build-cover 标志构建它,然后运行生成的二进制文件,同时设置环境变量 GOCOVERDIR 为覆盖率配置文件的输出目录。有关如何开始的更多信息,请参阅‘集成测试覆盖率’介绍页。有关设计和实现的详细信息,请参阅提案

Vet 工具

改进了对嵌套函数捕获循环变量的检测

vet 工具现在会报告在子测试函数体内部调用 T.Parallel() 后对循环变量的引用。此类引用可能会观察到来自不同迭代的变量值(通常导致测试用例被跳过)或由于非同步并发访问而导致无效状态。

该工具还在更多地方检测引用错误。以前它只考虑循环体的最后一条语句,但现在它会递归地检查 if、switch 和 select 语句中的最后一条语句。

针对不正确时间格式的新诊断

vet 工具现在会报告在 Time.Formattime.Parse 中使用时间格式 2006-02-01 (yyyy-dd-mm) 的情况。这种格式不常见于日期标准,但经常被误用,尤其是在尝试使用 ISO 8601 日期格式 (yyyy-mm-dd) 时。

运行时

垃圾收集器的一些内部数据结构被重新组织,以提高空间和 CPU 效率。这项更改减少了内存开销,并将整体 CPU 性能提高了至多 2%。

在某些情况下,垃圾收集器在处理 goroutine 协助时表现得更稳定。

Go 1.20 添加了一个新的 runtime/coverage 包,其中包含用于从不通过 os.Exit() 终止的长时间运行和/或服务器程序在运行时写入覆盖率配置文件数据的 API。

编译器

Go 1.20 添加了对配置文件引导优化(Profile-Guided Optimization, PGO)的预览支持。PGO 使工具链能够根据运行时配置文件信息执行应用程序和工作负载特定的优化。目前,编译器支持 pprof CPU 配置文件,这些可以通过常规方式收集,例如使用 runtime/pprofnet/http/pprof 包。要启用 PGO,请通过 -pgo 标志将 pprof 配置文件的路径传递给 go build 命令,如上文所述。Go 1.20 使用 PGO 在热点调用处更积极地进行函数内联。对一组代表性 Go 程序进行的基准测试显示,启用配置文件引导内联优化可将性能提升约 3-4%。详细文档请参阅PGO 用户指南。我们计划在未来的版本中添加更多的配置文件引导优化功能。请注意,配置文件引导优化是预览功能,请谨慎使用。

Go 1.20 编译器升级了其前端,采用了一种新的方式处理编译器的内部数据,这修复了几个泛型类型问题,并允许在泛型函数和方法内部进行类型声明。

编译器现在默认通过编译器错误拒绝匿名接口循环。这些循环源于内嵌接口的巧妙使用,一直存在微妙的正确性问题,但我们没有证据表明它们在实践中被实际使用。假设没有用户报告受到此更改的不利影响,我们计划在 Go 1.22 的语言规范中正式禁止它们,以便工具作者也可以停止支持它们。

Go 1.18 和 1.19 的构建速度有所下降,这主要是由于增加了对泛型的支持以及后续工作。Go 1.20 将构建速度提高了至多 10%,使其恢复到与 Go 1.17 相似的水平。与 Go 1.19 相比,生成的代码性能通常也有所改善。

链接器

在 Linux 上,链接器现在在链接时选择 glibcmusl 的动态解释器。

在 Windows 上,Go 链接器现在支持现代基于 LLVM 的 C 工具链。

Go 1.20 对编译器生成的符号使用 go:type: 前缀,而不是 go.type.。这避免了用户包名称以 go. 开头时产生的混淆。debug/gosym 包支持 Go 1.20 及更高版本构建的二进制文件的这种新命名约定。

自举

当从源代码构建 Go 发行版且未设置 GOROOT_BOOTSTRAP 时,Go 的先前版本会在目录 $HOME/go1.4(Windows 上为 %HOMEDRIVE%%HOMEPATH%\go1.4)中查找 Go 1.4 或更高版本的自举工具链。Go 1.18 和 Go 1.19 在回退到 $HOME/go1.4 之前,会首先查找 $HOME/go1.17$HOME/sdk/go1.17,这预示着自举 Go 1.20 时将需要使用 Go 1.17。Go 1.20 确实需要 Go 1.17 版本进行自举,但我们意识到应该采用自举工具链的最新小版本,因此它需要 Go 1.17.13。Go 1.20 在回退到 $HOME/go1.4 之前,会查找 $HOME/go1.17.13$HOME/sdk/go1.17.13(以支持那些硬编码路径为 $HOME/go1.4 但在那里安装了更新的 Go 工具链的系统)。将来,我们计划大约每年向前推进一次自举工具链,特别地,我们预计 Go 1.22 将需要 Go 1.20 的最终小版本进行自举。

标准库

新增 crypto/ecdh 包

Go 1.20 添加了一个新的 crypto/ecdh 包,为在 NIST 曲线和 Curve25519 上进行椭圆曲线 Diffie-Hellman 密钥交换提供了明确支持。

对于 ECDH,程序应使用 crypto/ecdh 包,而不是 crypto/elliptic 包中的底层功能;对于更高级的用例,应使用第三方模块。

包装多个错误

Go 1.20 扩展了对错误包装的支持,允许一个错误包装多个其他错误。

通过提供一个返回 []errorUnwrap 方法,一个错误 e 可以包装多个错误。

errors.Iserrors.As 函数已更新,可以检查包装了多个错误的错误。

fmt.Errorf 函数现在支持多次出现 %w 格式动词,这将使其返回一个包装了所有这些错误操作数的错误。

新增函数 errors.Join 返回一个包装了错误列表的错误。

HTTP ResponseController

新增类型 "net/http".ResponseController 提供了对 "net/http".ResponseWriter 接口未处理的扩展的、基于请求的功能的访问。

以前,我们通过定义 ResponseWriter 可以实现的可选接口(例如 Flusher来添加新的基于请求的功能。这些接口不易被发现且使用起来很笨拙。

ResponseController 类型提供了一种更清晰、更易于发现的方式来添加基于处理器的控制功能。Go 1.20 中新增的两个此类控制功能是 SetReadDeadlineSetWriteDeadline,它们允许为每个请求设置读写截止时间。例如

func RequestHandler(w ResponseWriter, r *Request) {
  rc := http.NewResponseController(w)
  rc.SetWriteDeadline(time.Time{}) // disable Server.WriteTimeout when sending a large response
  io.Copy(w, bigData)
}

新增 ReverseProxy Rewrite hook

httputil.ReverseProxy 转发代理包含一个新的 Rewrite hook 函数,取代了先前的 Director hook。

Rewrite hook 接受一个 ProxyRequest 参数,该参数包含代理接收到的入站请求和它将发送的出站请求。与仅操作出站请求的 Director hook 不同,这使得 Rewrite hook 能够避免某些场景,即恶意入站请求可能导致 hook 添加的头部在转发前被移除。参见issue #50580

ProxyRequest.SetURL 方法将出站请求路由到提供的目标地址,并取代了 NewSingleHostReverseProxy 函数。与 NewSingleHostReverseProxy 不同,SetURL 还会设置出站请求的 Host 头部。

ProxyRequest.SetXForwarded 方法设置出站请求的 X-Forwarded-ForX-Forwarded-HostX-Forwarded-Proto 头部。使用 Rewrite 时,默认不添加这些头部。

使用这些特性的 Rewrite hook 示例如下:

proxyHandler := &httputil.ReverseProxy{
  Rewrite: func(r *httputil.ProxyRequest) {
    r.SetURL(outboundURL) // Forward request to outboundURL.
    r.SetXForwarded()     // Set X-Forwarded-* headers.
    r.Out.Header.Set("X-Additional-Header", "header set by the proxy")
  },
}

当入站请求没有 User-Agent 头部时,ReverseProxy 不再向转发的请求添加 User-Agent 头部。

标准库的小改动

一如既往,标准库有各种小改动和更新,这些更改是在考虑 Go 1 兼容性承诺的基础上进行的。还有各种性能改进,此处不一一列举。

archive/tar

当设置了环境变量 GODEBUG=tarinsecurepath=0 时,对于文件名为绝对路径、指向当前目录之外的位置、包含无效字符,或(在 Windows 上)是保留名称(如 NUL)的条目,Reader.Next 方法现在将返回错误 ErrInsecurePath。Go 的未来版本可能会默认禁用不安全路径。

archive/zip

当设置了环境变量 GODEBUG=zipinsecurepath=0 时,当打开包含文件名为绝对路径、指向当前目录之外的位置、包含无效字符,或(在 Windows 上)是保留名称(如 NUL)的任何文件名的归档文件时,NewReader 现在将返回错误 ErrInsecurePath。Go 的未来版本可能会默认禁用不安全路径。

现在,从包含文件数据的目录文件读取时将返回错误。zip 规范不允许目录文件包含文件数据,因此此更改仅影响从无效归档文件读取。

bytes

新增函数 CutPrefixCutSuffix 类似于 TrimPrefixTrimSuffix,但也会报告字符串是否被修剪。

新增函数 Clone 分配并返回一个字节 slice 的副本。

context

新增函数 WithCancelCause 提供了一种使用给定错误取消 context 的方法。可以通过调用新增函数 Cause 来检索该错误。

crypto/ecdsa

当使用支持的曲线时,所有操作现在都以恒定时间实现。这导致 CPU 时间增加了约 5% 到 30%,主要影响 P-384 和 P-521。

新增方法 PrivateKey.ECDHecdsa.PrivateKey 转换为 ecdh.PrivateKey

crypto/ed25519

PrivateKey.Sign 方法和 VerifyWithOptions 函数现在支持使用 Ed25519ph 对预哈希消息进行签名,这通过返回 crypto.SHA512Options.HashFunc 表示。它们现在还支持带有 context 的 Ed25519ctx 和 Ed25519ph,这通过设置新增的 Options.Context 字段表示。

crypto/rsa

新增字段 OAEPOptions.MGFHash 允许为 OAEP 解密单独配置 MGF1 哈希函数。

crypto/rsa 现在使用了一个新的、更安全的、恒定时间的后端。这导致解密操作的 CPU 运行时增加了约 15% (amd64 上的 RSA-2048) 到 45% (arm64 上的 RSA-4096),在 32 位架构上增加更多。加密操作比以前慢约 20 倍(但仍然比解密快 5-10 倍)。预计性能将在未来的版本中得到提升。程序不得修改或手动生成 PrecomputedValues 的字段。

crypto/subtle

新增函数 XORBytes 对两个字节 slice 进行异或操作。

crypto/tls

现在,解析过的证书会在所有正在使用该证书的客户端之间共享。这对于向共享证书链任何部分的服务器或一组服务器建立大量并发连接的程序来说,可以显著节省内存。

对于由于证书验证失败导致的握手失败,TLS 客户端和服务器现在会返回一个新增类型 CertificateVerificationError 的错误,该错误包含所呈现的证书。

crypto/x509

ParsePKCS8PrivateKeyMarshalPKCS8PrivateKey 现在支持类型为 *crypto/ecdh.PrivateKey 的密钥。ParsePKIXPublicKeyMarshalPKIXPublicKey 现在支持类型为 *crypto/ecdh.PublicKey 的密钥。解析 NIST 曲线密钥仍然返回类型为 *ecdsa.PublicKey*ecdsa.PrivateKey 的值。使用它们新增的 ECDH 方法转换为 crypto/ecdh 类型。

新增函数 SetFallbackRoots 允许程序定义一组备用根证书,以防操作系统验证器或标准平台根证书包在运行时不可用。它最常与一个新包 golang.org/x/crypto/x509roots/fallback 一起使用,该包将提供一个最新的根证书包。

debug/elf

现在,尝试使用 Section.Data 或由 Section.Open 返回的 reader 从 SHT_NOBITS 段读取时将返回错误。

定义了额外的 R_LARCH_* 常量,用于 LoongArch 系统。

定义了额外的 R_PPC64_* 常量,用于 PPC64 ELFv2 重定位。

R_PPC64_SECTOFF_LO_DS 的常量值已更正,从 61 改为 62。

debug/gosym

由于 Go 的符号命名约定发生了变化,处理 Go 二进制文件的工具应使用 Go 1.20 的 debug/gosym 包来透明地处理新旧二进制文件。

debug/pe

定义了额外的 IMAGE_FILE_MACHINE_RISCV* 常量,用于 RISC-V 系统。

encoding/binary

ReadVarintReadUvarint 函数现在在读取部分值后将返回 io.ErrUnexpectedEOF 错误,而不是 io.EOF

encoding/xml

新增方法 Encoder.Close 可用于在编码完成后检查未关闭的元素。

解码器现在拒绝包含多个冒号的元素和属性名称(例如 <a:b:c>),以及解析为空字符串的命名空间(例如 xmlns:a="")。

解码器现在拒绝在开始标签和结束标签中使用不同命名空间前缀的元素,即使这些前缀都指向同一个命名空间。

errors

新增函数 Join 返回一个包装了错误列表的错误。

fmt

Errorf 函数支持多次出现 %w 格式动词,返回一个可以解包为 %w 所有参数列表的错误。

新增函数 FormatString 恢复对应于 State 的格式化指令,这在 Formatter 实现中可能很有用。

go/ast

新增字段 RangeStmt.Range 记录了 range 语句中 range 关键字的位置。

新增字段 File.FileStartFile.FileEnd 记录了整个源文件的开始和结束位置。

go/token

新增方法 FileSet.RemoveFileFileSet 中移除一个文件。长时间运行的程序可以使用此方法释放与不再需要的文件相关的内存。

go/types

新增函数 Satisfies 报告一个类型是否满足约束。此更改与新语言语义保持一致,新语义区分了满足约束和实现接口。

html/template

Go 1.20.3 及更高版本禁止在 ECMAScript 6 模板字面量中使用 actions。此行为可通过设置 GODEBUG=jstmpllitinterp=1 恢复。

io

新增类型 OffsetWriter 包装了一个底层的 WriterAt,并提供了 SeekWriteWriteAt 方法,这些方法通过一个固定量调整其有效的文件偏移位置。

io/fs

新增错误 SkipAll 立即终止 WalkDir,但以成功状态结束。

math/big

math/big 包的范围广泛且时序依赖于输入,这使得它不适合实现密码学。标准库中的密码学包不再对攻击者控制的输入调用非平凡的 Int 方法。将来,确定 math/big 中的 bug 是否被视为安全漏洞将取决于其对标准库的更广泛影响。

math/rand

math/rand 包现在会自动使用一个随机值对全局随机数生成器(由 Float64Int 等顶级函数使用)进行播种(seeding),并且顶级的 Seed 函数已被弃用。需要可重现随机数序列的程序应优先分配自己的随机源,使用 rand.New(rand.NewSource(seed))

需要之前一致的全局播种行为的程序可以在其环境中设置 GODEBUG=randautoseed=0

顶级的 Read 函数已被弃用。在几乎所有情况下,crypto/rand.Read 更适用。

mime

ParseMediaType 函数现在允许重复的参数名称,只要名称的值相同即可。

mime/multipart

Reader 类型的方法现在会包装底层 io.Reader 返回的错误。

在 Go 1.19.8 及更高版本中,此包对其处理的 MIME 数据大小设置了限制,以防恶意输入。Reader.NextPartReader.NextRawPart 将一个部分的头部数量限制为 10000,Reader.ReadForm 将所有 FileHeaders 中的总头部数量限制为 10000。这些限制可通过设置 GODEBUG=multipartmaxheaders 进行调整。Reader.ReadForm 进一步将表单中的部分数量限制为 1000。此限制可通过设置 GODEBUG=multipartmaxparts 进行调整。

net

LookupCNAME 函数现在在存在 CNAME 记录时,始终返回其内容。以前在 Unix 系统上以及使用纯 Go 解析器时,如果 CNAME 记录指向一个没有 AAAAACNAME 记录的名称,LookupCNAME 会返回错误。这项更改修改了 LookupCNAME,使其与之前在 Windows 上的行为一致,允许 LookupCNAMECNAME 记录存在时成功。

Interface.Flags 现在包含新增标志 FlagRunning,表示一个操作上活动的接口。一个已配置但未活动的接口(例如,由于网线未连接)将设置 FlagUp,但不设置 FlagRunning

新增字段 Dialer.ControlContext 包含一个回调函数,类似于现有的 Dialer.Control hook,该回调函数额外接受 dial context 作为参数。当 ControlContext 不为 nil 时,Control 将被忽略。

Go DNS 解析器识别 trust-ad 解析器选项。当 resolv.conf 中设置了 options trust-ad 时,Go 解析器将在 DNS 查询中设置 AD 位。解析器不会使用响应中的 AD 位。

DNS 解析将检测 /etc/nsswitch.conf 的更改并在文件更改时重新加载。检查频率最高为每五秒一次,与之前处理 /etc/hosts/etc/resolv.conf 的方式一致。

net/http

ResponseWriter.WriteHeader 函数现在支持发送 1xx 状态码。

新增配置设置 Server.DisableGeneralOptionsHandler 允许禁用默认的 OPTIONS * 处理器。

新的 Transport.OnProxyConnectResponse 钩子在 Transport 接收到代理针对 CONNECT 请求的 HTTP 响应时被调用。

HTTP 服务器现在接受包含正文的 HEAD 请求,而不是将其拒绝为无效。

net/http 函数返回的 HTTP/2 流错误可以使用 errors.As 转换为 golang.org/x/net/http2.StreamError

现在会修剪 cookie 名称前后的空格,而不是将其拒绝为无效。例如,cookie 设置 "name =value" 现在被接受为设置 cookie "name"。

Expires 字段为空的 Cookie 现在被视为有效。Cookie.Valid 只在 Expires 字段设置时进行检查。

net/netip

新的 IPv6LinkLocalAllRoutersIPv6Loopback 函数是 net.IPv6loopbacknet.IPv6linklocalallroutersnet/netip 包中的等价物。

os

在 Windows 上,名称 NULMkdirStat 中不再被视为特殊情况。

在 Windows 上,File.Stat 现在在文件是目录时使用文件句柄来检索属性。以前它会使用传递给 Open 的路径,如果文件已被移动或替换,该路径可能不再代表文件句柄所指向的文件。此更改修改了 Open 在打开目录时不再使用 FILE_SHARE_DELETE 访问权限,这与普通文件的行为一致。

在 Windows 上,File.Seek 现在支持定位到目录的开头。

os/exec

新的 Cmd 字段 CancelWaitDelay 指定当 Cmd 关联的 Context 被取消,或者其进程退出时 I/O 管道仍被子进程占用时的 Cmd 行为。

path/filepath

新的错误 SkipAll 会立即终止 Walk,但视为成功。

新的 IsLocal 函数报告一个路径是否在词法上位于某个目录的本地。例如,如果 IsLocal(p)true,则 Open(p) 将引用一个词法上位于当前目录根目录下的子树中的文件。

reflect

新的 Value.ComparableValue.Equal 方法可用于比较两个 Value 是否相等。Comparable 报告 Equal 对于给定的 Value 接收者是否是一个有效的操作。

新的 Value.Grow 方法扩展一个切片,以保证为另外 n 个元素留出空间。

新的 Value.SetZero 方法将一个值设置为其类型的零值。

Go 1.18 引入了 Value.SetIterKeyValue.SetIterValue 方法。这些是优化:v.SetIterKey(it) 本应等同于 v.Set(it.Key())。实现中错误地省略了对未导出字段使用的检查,而该检查在非优化形式中是存在的。Go 1.20 纠正了这些方法,使其包含未导出字段的检查。

regexp

Go 1.19.2 和 Go 1.18.7 对正则表达式解析器包含了一个安全修复,使其拒绝会消耗过多内存的超大表达式。由于 Go 补丁版本不会引入新的 API,解析器在这种情况下返回 syntax.ErrInternalError。Go 1.20 添加了一个更具体的错误 syntax.ErrLarge,解析器现在返回该错误。

runtime/cgo

Go 1.20 添加了新的 Incomplete 标记类型。cgo 生成的代码将使用 cgo.Incomplete 来标记一个不完整的 C 类型。

runtime/metrics

Go 1.20 添加了新的 支持的指标,包括当前的 GOMAXPROCS 设置 (/sched/gomaxprocs:threads),执行的 cgo 调用次数 (/cgo/go-to-c-calls:calls),互斥锁总阻塞时间 (/sync/mutex/wait/total:seconds),以及垃圾回收中花费时间的各种度量。

基于时间直方图的指标现在精度较低,但占用的内存少得多。

runtime/pprof

互斥锁分析样本现在进行预缩放,解决了如果在执行期间采样率发生变化,旧的互斥锁分析样本缩放不正确的问题。

在 Windows 上收集的分析现在包含内存映射信息,修复了位置无关二进制文件的符号化问题。

runtime/trace

垃圾收集器的后台清理器现在让出 CPU 的频率降低,从而在执行跟踪中产生的无关事件大大减少。

strings

新的 CutPrefixCutSuffix 函数类似于 TrimPrefixTrimSuffix,但还会报告字符串是否被修剪。

sync

新的 Map 方法 SwapCompareAndSwapCompareAndDelete 允许原子地更新现有 map 条目。

syscall

在 FreeBSD 上,对 FreeBSD 11 及更早版本所需的兼容层已被移除。

在 Linux 上,为配合 SysProcAttr.Cloneflags 字段的使用,定义了额外的 CLONE_* 常量。

在 Linux 上,新的 SysProcAttr.CgroupFDSysProcAttr.UseCgroupFD 字段提供了一种将子进程放入特定 cgroup 的方法。

testing

新方法 B.Elapsed 报告当前基准测试的已用时间,这对于计算与 ReportMetric 一起报告的速率可能很有用。

从传递给 T.Cleanup 的函数中调用 T.Run 从未明确定义,现在将引发 panic。

time

新的时间布局常量 DateTimeDateOnlyTimeOnly 为公共 Go 源代码调查中使用的三种最常见的布局字符串提供了名称。

新的 Time.Compare 方法比较两个时间。

Parse 现在忽略输入中的亚纳秒精度,而不是将这些数字报告为错误。

Time.MarshalJSON 方法现在更严格地遵循 RFC 3339。

unicode/utf16

新的 AppendRune 函数将给定 rune 的 UTF-16 编码附加到 uint16 切片,类似于 utf8.AppendRune