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
包定义了三个新函数:SliceData
、String
和 StringData
。与 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 build
和 go 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 build
、go install
以及其他与构建相关的命令现在支持 -pgo
标志,该标志用于启用配置文件引导优化(profile-guided optimization),这将在下面的编译器部分详细描述。-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
在没有 C 工具链的系统上,go
命令现在默认禁用 cgo
。更具体地说,当未设置 CGO_ENABLED
环境变量、未设置 CC
环境变量且路径中找不到默认的 C 编译器(通常是 clang
或 gcc
)时,CGO_ENABLED
默认为 0
。像往常一样,您可以通过显式设置 CGO_ENABLED
来覆盖默认值。
这项默认更改最重要的影响是,当 Go 安装在没有 C 编译器的系统上时,它现在将对使用 cgo 的标准库包使用纯 Go 构建,而不再使用预发布的包归档(这些已被移除,如上文所述),或尝试使用 cgo 却失败。这使得 Go 在一些最小化的容器环境以及 macOS 上运行得更好,因为自 Go 1.16 以来,macOS 上基于 cgo 的包就未使用预发布的包归档了。
标准库中使用 cgo 的包是 net
、os/user
和 plugin
。在 macOS 上,net
和 os/user
包已被重写,不再使用 cgo:现在 cgo 和非 cgo 构建以及交叉编译构建都使用相同的代码。在 Windows 上,net
和 os/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.Format
和 time.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/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 工具链的系统)。将来,我们计划大约每年向前推进一次自举工具链,特别地,我们预计 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 扩展了对错误包装的支持,允许一个错误包装多个其他错误。
通过提供一个返回 []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{}) // 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-For
、X-Forwarded-Host
和 X-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
新增函数 CutPrefix
和 CutSuffix
类似于 TrimPrefix
和 TrimSuffix
,但也会报告字符串是否被修剪。
新增函数 Clone
分配并返回一个字节 slice 的副本。
context
新增函数 WithCancelCause
提供了一种使用给定错误取消 context 的方法。可以通过调用新增函数 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
表示。它们现在还支持带有 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
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
返回的 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
ReadVarint
和 ReadUvarint
函数现在在读取部分值后将返回 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.FileStart
和 File.FileEnd
记录了整个源文件的开始和结束位置。
go/token
新增方法 FileSet.RemoveFile
从 FileSet
中移除一个文件。长时间运行的程序可以使用此方法释放与不再需要的文件相关的内存。
go/types
新增函数 Satisfies
报告一个类型是否满足约束。此更改与新语言语义保持一致,新语义区分了满足约束和实现接口。
html/template
Go 1.20.3 及更高版本禁止在 ECMAScript 6 模板字面量中使用 actions。此行为可通过设置 GODEBUG=jstmpllitinterp=1
恢复。
io
新增类型 OffsetWriter
包装了一个底层的 WriterAt
,并提供了 Seek
、Write
和 WriteAt
方法,这些方法通过一个固定量调整其有效的文件偏移位置。
io/fs
新增错误 SkipAll
立即终止 WalkDir
,但以成功状态结束。
math/big
math/big 包的范围广泛且时序依赖于输入,这使得它不适合实现密码学。标准库中的密码学包不再对攻击者控制的输入调用非平凡的 Int 方法。将来,确定 math/big 中的 bug 是否被视为安全漏洞将取决于其对标准库的更广泛影响。
math/rand
math/rand 包现在会自动使用一个随机值对全局随机数生成器(由 Float64
和 Int
等顶级函数使用)进行播种(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.NextPart
和 Reader.NextRawPart
将一个部分的头部数量限制为 10000,Reader.ReadForm
将所有 FileHeaders
中的总头部数量限制为 10000。这些限制可通过设置 GODEBUG=multipartmaxheaders
进行调整。Reader.ReadForm
进一步将表单中的部分数量限制为 1000。此限制可通过设置 GODEBUG=multipartmaxparts
进行调整。
net
LookupCNAME
函数现在在存在 CNAME
记录时,始终返回其内容。以前在 Unix 系统上以及使用纯 Go 解析器时,如果 CNAME
记录指向一个没有 A
、AAAA
或 CNAME
记录的名称,LookupCNAME
会返回错误。这项更改修改了 LookupCNAME
,使其与之前在 Windows 上的行为一致,允许 LookupCNAME
在 CNAME
记录存在时成功。
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
新的 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 管道仍被子进程占用时的 Cmd
行为。
path/filepath
新的错误 SkipAll
会立即终止 Walk
,但视为成功。
新的 IsLocal
函数报告一个路径是否在词法上位于某个目录的本地。例如,如果 IsLocal(p)
为 true
,则 Open(p)
将引用一个词法上位于当前目录根目录下的子树中的文件。
reflect
新的 Value.Comparable
和 Value.Equal
方法可用于比较两个 Value
是否相等。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:seconds
),以及垃圾回收中花费时间的各种度量。
基于时间直方图的指标现在精度较低,但占用的内存少得多。
runtime/pprof
互斥锁分析样本现在进行预缩放,解决了如果在执行期间采样率发生变化,旧的互斥锁分析样本缩放不正确的问题。
在 Windows 上收集的分析现在包含内存映射信息,修复了位置无关二进制文件的符号化问题。
runtime/trace
垃圾收集器的后台清理器现在让出 CPU 的频率降低,从而在执行跟踪中产生的无关事件大大减少。
strings
新的 CutPrefix
和 CutSuffix
函数类似于 TrimPrefix
和 TrimSuffix
,但还会报告字符串是否被修剪。
sync
新的 Map
方法 Swap
、CompareAndSwap
和 CompareAndDelete
允许原子地更新现有 map 条目。
syscall
在 FreeBSD 上,对 FreeBSD 11 及更早版本所需的兼容层已被移除。
在 Linux 上,为配合 SysProcAttr.Cloneflags
字段的使用,定义了额外的 CLONE_*
常量。
在 Linux 上,新的 SysProcAttr.CgroupFD
和 SysProcAttr.UseCgroupFD
字段提供了一种将子进程放入特定 cgroup 的方法。
testing
新方法 B.Elapsed
报告当前基准测试的已用时间,这对于计算与 ReportMetric
一起报告的速率可能很有用。
从传递给 T.Cleanup
的函数中调用 T.Run
从未明确定义,现在将引发 panic。
time
新的时间布局常量 DateTime
、DateOnly
和 TimeOnly
为公共 Go 源代码调查中使用的三种最常见的布局字符串提供了名称。
新的 Time.Compare
方法比较两个时间。
Parse
现在忽略输入中的亚纳秒精度,而不是将这些数字报告为错误。
Time.MarshalJSON
方法现在更严格地遵循 RFC 3339。
unicode/utf16
新的 AppendRune
函数将给定 rune 的 UTF-16 编码附加到 uint16 切片,类似于 utf8.AppendRune
。