编程

Go语言 1.20 版本正式发布

996 2023-02-03 04:21:57

最新的 Go 版本 1.20 在 Go 1.19 发布六个月后发布。 它的大部分更改都在工具链、运行时和库的实现中。 一如既往,该版本保持了 Go 1 的兼容性承诺。 我们期望几乎所有的 Go 程序都能像以前一样继续编译和运行。

语言的变化

Go 1.20 包含对语言的四个更改。

Go 1.17 添加了从切片到数组指针的转换。 Go 1.20 扩展了它以允许从切片到数组的转换:给定切片 x,现在可以写成[4]byte(x)而不是 *(*[4]byte)(x)。

unsafe 包定义了三个新函数 SliceData、String 和 StringData。 与 Go 1.17 的 Slice 一起,这些函数现在提供了构建和解构切片和字符串值的完整能力,而不依赖于它们的确切表示。

该规范现在定义结构值一次比较一个字段,按照它们在结构类型定义中出现的顺序考虑字段,并在第一个不匹配时停止。类似地,该规范现在定义数组值按递增索引顺序一次比较一个元素。 在这两种情况下,差异会影响某些比较是否必须抛出(panic)。

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

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 设置为在每个测试程序执行开始时启动。 当使用 go 命令运行多个测试时,这些启动事件保证以与命令行中指定的包相同的顺序发出。

go 命令现在定义架构特性构建标签,例如 amd64.v2,以允许根据特定架构特性的存在或不存在来选择包实现文件。 有关详细信息,请参阅 go help buildconstraint。

go 子命令现在接受 -C

以在执行命令之前将目录更改为 ,这对于需要在多个不同模块中执行命令的脚本可能很有用。

go build 和 go test 命令不再接受 -i 标志,该标志自 Go 1.16 以来已被弃用。

go generate 命令现在接受 -skip 以跳过 //go:generate 匹配 的指令。

go test 命令现在接受 -skip 以跳过测试、子测试或匹配 的示例。

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

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

go build、go install 和其他与构建相关的命令现在支持一个 -cover 标志,该标志使用代码覆盖检测构建指定的目标。 这在下面的封面部分中有更详细的描述。

go version

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

Cgo

go 命令现在在没有 C 工具链的系统上默认禁用 cgo。 更具体地说,当取消设置 CGO_ENABLED 环境变量,取消设置 CC 环境变量,并且在路径中找不到默认的 C 编译器(通常是 clang 或 gcc)时,CGO_ENABLED 默认为 0。与往常一样,您可以覆盖默认值 明确设置 CGO_ENABLED。

默认更改最重要的影响是,当 Go 安装在没有 C 编译器的系统上时,它现在将使用纯 Go 构建标准库中使用 cgo 的包,而不是使用预分发的包存档(已被删除,如上所述)或尝试使用 cgo 并失败。 这使得 Go 在一些最小的容器环境以及 macOS 上工作得更好,在 macOS 上,自 Go 1.16 以来,预分发的包存档没有用于基于 cgo 的包。

标准库中使用cgo的包有net、os/user和plugin。 在 macOS 上,net 和 os/user 包已被重写为不使用 cgo:相同的代码现在用于 cgo 和非 cgo 构建以及交叉编译的构建。 在 Windows 上,net 和 os/user 包未使用过 cgo。 在其他系统上,禁用 cgo 的构建将使用这些包的纯 Go 版本。

在 macOS 上,竞态检测器已被重写为不使用 cgo:启用竞态检测器的程序可以在没有 Xcode 的情况下构建和运行。 在 Linux 和其他 Unix 系统以及 Windows 上,需要主机 C 工具链才能使用竞争检测器。

代码覆盖率

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

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

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

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

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

针对错误时间格式的新诊断

vet 工具现在报告时间格式 2006-02-01 (yyyy-dd-mm) 与 Time.Format 和 time.Parse 的使用。 此格式未出现在通用日期标准中,但在尝试使用 ISO 8601 日期格式 (yyyy-mm-dd) 时经常被错误使用。

运行时

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

在某些情况下,垃圾收集器在 goroutine 协助方面表现得不太不稳定。

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

编译器

Go 1.20 添加了对配置文件引导优化 (PGO) 的预览支持。 PGO 使工具链能够根据运行时配置文件信息执行特定于应用程序和工作负载的优化。 目前,编译器支持 pprof CPU 配置文件,可以通过常规方式收集,例如 runtime/pprof 或 net/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 上,链接器现在在链接时为 glibc 或 musl 选择动态解释器。

在 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 1.22 将需要 Go 1.20 的最终版本来进行引导。

核心库

新的crypto/ecdh 包

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

程序应该使用 crypto/ecdh,而不是用于 ECDH 的 crypto/elliptic 中的低级功能,以及用于更高级用例的第三方模块。

包装多个错误

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

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

errors.Is 和 errors.As 函数已更新以检查多重包装错误。

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

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

HTTP ResponseController

新的“net/http”.ResponseController 类型提供对“net/http”.ResponseWriter 接口未处理的扩展的按请求功能的访问。

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

ResponseController 类型提供了一种更清晰、更易于发现的方式来添加每个处理程序的控件。 Go 1.20 中还添加了两个这样的控件,它们是 SetReadDeadline 和 SetWriteDeadline,它们允许设置每个请求的读写截止日期。 例如:

func RequestHandler(w ResponseWriter, r *Request) {
  rc := http.NewResponseController(w)
  rc.SetWriteDeadline(time.Time{}) // 发送大响应时禁用 Server.WriteTimeout
  io.Copy(w, 大数据)
}

新增 ReverseProxy Rewrite钩子

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

Rewrite钩子接受 ProxyRequest 参数,该参数包括代理接收的入站请求和它将发送的出站请求。 与仅对出站请求进行操作的 Director 钩子不同,这允许重写钩子避免某些情况,在这种情况下,恶意入站请求可能导致钩子添加的标头在转发之前被删除。 请参阅问题 #50580。

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

ProxyRequest.SetXForwarded 方法设置出站请求的 X-Forwarded-For、X-Forwarded-Host 和 X-Forwarded-Proto 标头。 使用重写时,默认情况下不会添加这些标头。

使用这些功能的重写钩子的示例是:

proxyHandler := &httputil.ReverseProxy{
  Rewrite:func(r *httputil.ProxyRequest) {
    r.SetURL(outboundURL) // 转发请求到 outboundURL。
    r.SetXForwarded() // 设置 X-Forwarded-* 标头。
    r.Out.Header.Set("X-Additional-Header", "代理设置的header")
  },
}

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

库的改动

与往常一样,库有各种小的变化和更新,考虑到 Go 1 的兼容性承诺。 还有各种性能提升,这里就不一一列举了。

archive/tar

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

archive/zip

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

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

bytes

新的 CutPrefix 和 CutSuffix 函数类似于 TrimPrefix 和 TrimSuffix,但还会报告字符串是否被修剪。

新的 Clone 函数分配字节切片的副本。

context

新的 WithCancelCause 函数提供了一种方法来取消具有给定错误的上下文。 可以通过调用新的 Cause 函数来检索该错误。

crypto/ecdsa

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

新的 PrivateKey.ECDH 方法将 ecdsa.PrivateKey 转换为 ecdh.PrivateKey。

crypto/ed25519

PrivateKey.Sign 方法和 VerifyWithOptions 函数现在支持使用 Ed25519ph 对预散列消息进行签名,由返回 crypto.SHA512 的 Options.HashFunc 表示。 他们现在还支持带上下文的 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

新函数 XOR Bytes 将两个字节片异或在一起。

crypto/TLS

已解析的证书现在在所有主动使用该证书的客户端之间共享。 在与共享其证书链的任何部分的服务器或服务器集合建立许多并发连接的程序中,内存节省可能非常重要。

对于由于证书验证失败而导致的握手失败,TLS 客户端和服务器现在返回新类型 CertificateVerificationError 的错误,其中包括提供的证书。

crypto/x509

ParsePKCS8PrivateKey 和 MarshalPKCS8PrivateKey 现在支持 *crypto/ecdh.PrivateKey 类型的密钥。 ParsePKIXPublicKey 和 MarshalPKIXPublicKey 现在支持 *crypto/ecdh.PublicKey 类型的密钥。 解析 NIST 曲线密钥仍然会返回 *ecdsa.PublicKey 和 *ecdsa.PrivateKey 类型的值。 使用他们新的 ECDH 方法转换为 crypto/ecdh 类型。

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

debug/elf

尝试使用 Section.Data 或 Section.Open 返回的读取器从 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

ReadVarint 和 ReadUvarint 函数现在将在读取部分值后返回 io.ErrUnexpectedEOF,而不是 io.EOF。

encoding/xml

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

解码器现在拒绝具有多个冒号的元素和属性名称,例如 ,以及解析为空字符串的名称空间,例如 xmlns:a=""。

解码器现在拒绝在开始和结束标记中使用不同命名空间前缀的元素,即使这些前缀都表示相同的命名空间。

errors

新的 Join 函数返回一个包含错误列表的错误。

fmt

Errorf 函数支持多次出现 %w 格式动词,返回一个错误,该错误展开到 %w 的所有参数列表。

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

go/ast

新的 RangeStmt.Range 字段记录范围关键字在范围语句中的位置。

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

go/token

新的 FileSet.RemoveFile 方法从 FileSet 中删除文件。 长时间运行的程序可以使用它来释放与它们不再需要的文件关联的内存。

go/types

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

io

新的 OffsetWriter 包装了一个底层 WriterAt,并提供了 Seek、Write 和 WriteAt 方法,这些方法可以将它们的有效文件偏移位置调整一个固定的量。

io/fs

新错误 SkipAll 立即但成功地终止了 WalkDir。

math/big

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

math/rand

math/rand 包现在自动使用随机值为全局随机数生成器(由 Float64 和 Int 等顶级函数使用)提供种子,并且顶级 Seed 函数已被弃用。 需要可重现的随机数序列的程序应该更喜欢使用 rand.New(rand.NewSource(seed)) 分配它们自己的随机源。

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

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

mime

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

mime/multipart

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

net

LookupCNAME 函数现在始终返回存在的 CNAME 记录的内容。 以前在 Unix 系统上和使用纯 Go 解析器时,如果 CNAME 记录引用没有 A、AAAA 或 CNAME 记录的名称,LookupCNAME 将返回错误。 此更改修改了 LookupCNAME 以匹配以前在 Windows 上的行为,从而允许 LookupCNAME 在 CNAME 存在时成功。

Interface.Flags 现在包括新标志 FlagRunning,表示一个可操作的活动接口。 管理配置但未激活的接口(例如,因为未连接网络电缆)将设置 FlagUp 但不设置 FlagRunning。

新的 Dialer.ControlContext 字段包含一个类似于现有 Dialer.Control 挂钩的回调函数,它另外接受拨号上下文作为参数。 当 ControlContext 不为零时,控制将被忽略。

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

DNS 解析将检测对 /etc/nsswitch.conf 的更改并在更改时重新加载文件。 检查最多每五秒一次,与之前对 /etc/hosts 和 /etc/resolv.conf 的处理相匹配。

net/http

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

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

当传输从代理接收到 CONNECT 请求的 HTTP 响应时,将调用新的 Transport.OnProxyConnectResponse 挂钩。

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

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

前导和尾随空格从 cookie 名称中删除,而不是被拒绝为无效。 例如,“name =value”的 cookie 设置现在被接受为设置 cookie“name”。

net/netip

新的 IPv6LinkLocalAllRouters 和 IPv6Loopback 函数是 net.IPv6loopback 和 net.IPv6linklocalallrouters 的 net/netip 等价物。

os

在 Windows 上,名称 NUL 不再被视为 Mkdir 和 Stat 中的特例。

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

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

os/exec

新的 Cmd 字段 Cancel 和 WaitDelay 指定 Cmd 在其关联的 Context 被取消或其进程退出时 I/O 管道仍由子进程保持打开状态时的行为。

path/filepath

新错误 SkipAll 会立即但成功地终止 Walk。

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

reflect

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

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

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

Go 1.18 引入了 Value.SetIterKey 和 Value.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),以及垃圾收集所花费时间的各种度量。

基于时间的直方图指标现在不太精确,但占用的内存少得多。

runtime/pprof

互斥配置文件样本现在已预先缩放,解决了如果采样率在执行期间发生变化,旧的互斥配置文件样本将被错误缩放的问题。

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

runtime/trace

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

strings

新的 CutPrefix 和 CutSuffix 函数类似于 TrimPrefix 和 TrimSuffix,但还会报告字符串是否被修剪。

新的 Clone 函数分配一个字符串的副本。

sync

新的 Map 方法 Swap、CompareAndSwap 和 CompareAndDelete 允许以原子方式更新现有的映射条目。

syscall

在 FreeBSD 上,FreeBSD 11 及更早版本所需的兼容性垫片已被删除。

在 Linux 上,额外的 CLONE_* 常量被定义为与 SysProcAttr.Cloneflags 字段一起使用。

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

testing

新方法 B.Elapsed 报告基准的当前经过时间,这可能有助于计算使用 ReportMetric 报告的速率。

time

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

新的 Time.Compare 方法比较两次。

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

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

unicode/utf16

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