Go 1.21 发布说明
Go 1.21 简介
最新发布的 Go 1.21 版本在 Go 1.20 发布六个月后推出。其大部分改动集中在工具链、运行时和标准库的实现上。一如既往,此版本遵循 Go 1 的兼容性承诺;事实上,Go 1.21 在这一承诺上有所改进。我们预计几乎所有 Go 程序都能像以前一样继续编译和运行。
Go 1.21 对版本编号引入了一个小改动。过去,我们使用 Go 1.N 来指代整体的 Go 语言版本、版本系列以及该系列中的首个版本。从 Go 1.21 开始,首个版本现在是 Go 1.N.0。今天,我们发布了 Go 1.21 语言及其初始实现 Go 1.21.0 版本。这些发布说明提及“Go 1.21”;而像 go
version
这样的工具将报告“go1.21.0
”(直到您升级到 Go 1.21.1)。有关新版本编号的详细信息,请参阅“Go 工具链”文档中的“Go 版本”部分。
语言变化
Go 1.21 在语言中增加了三个新的内置函数。
-
新的函数
min
和max
计算给定固定数量参数中的最小值(或最大值,对于max
)。有关详细信息,请参阅语言规范的详细说明。 -
新的函数
clear
删除 map 中的所有元素或将 slice 中的所有元素归零。有关详细信息,请参阅语言规范的详细说明。
包初始化顺序现在规定得更精确。新的算法是:
- 按导入路径对所有包进行排序。
- 重复直到包列表为空
- 在列表中找到所有导入都已初始化的首个包。
- 初始化该包并将其从列表中移除。
这可能会改变某些程序的行为,这些程序依赖于未通过显式导入表达的特定初始化顺序。在过去的版本中,这些程序的行为在规范中并未得到明确定义。新规则提供了明确的定义。
对类型推断进行了多项改进,提高了其能力和精度。
- 一个(可能部分实例化的泛型)函数现在可以接受本身就是(可能部分实例化的)泛型函数作为参数进行调用。编译器将尝试推断被调用的泛型函数缺失的类型实参(与之前一样),并且对于未完全实例化的泛型函数参数,编译器还将推断其缺失的类型实参(新增)。典型用例是对容器(例如 slices.IndexFunc)进行操作的泛型函数的调用,其中函数参数也可以是泛型的,并且被调函数及其参数的类型实参是从容器类型推断出来的。更一般地说,如果类型实参可以从赋值中推断出来,泛型函数现在可以在赋值给变量或作为结果值返回时无需显式实例化即可使用。
- 将值赋给接口时,类型推断现在还会考虑方法:方法签名中使用的类型参数的类型实参可以从匹配方法的对应参数类型中推断出来。
- 类似地,由于类型实参必须实现其对应约束的所有方法,因此类型实参和约束的方法会进行匹配,这可能导致推断出额外的类型实参。
- 如果将不同种类的多个无类型常量参数(例如无类型 int 和无类型浮点常量)传递给具有相同(未另行指定)类型参数类型的参数,现在类型推断不会报错,而是使用与带有无类型常量操作数的运算符相同的方法确定类型。此更改使从无类型常量参数推断出的类型与常量表达式的类型保持一致。
- 在赋值中匹配对应类型时,类型推断现在更加精确:组件类型(例如切片元素或函数签名中的参数类型)必须相同(给定合适的类型实参)才能匹配,否则推断失败。此更改会生成更准确的错误消息:过去类型推断可能会错误地成功并导致无效赋值,而现在如果两个类型无法匹配,编译器会报告推断错误。
更普遍地,语言规范中关于类型推断的描述已得到澄清。总而言之,所有这些更改使得类型推断更强大,推断失败更不易令人惊讶。
Go 1.21 包含我们正在考虑在未来版本的 Go 中引入的语言变更预览:将 for 循环变量设置为按迭代而不是按循环作用域,以避免意外的共享 bug。有关如何尝试该语言变更的详细信息,请参阅 LoopvarExperiment Wiki 页面。
Go 1.21 现在规定,如果 goroutine 发生 panic 并且 recover 由延迟函数直接调用,则 recover 的返回值保证不为 nil。为确保这一点,使用 nil 接口值(或无类型 nil)调用 panic 会导致类型为 *runtime.PanicNilError
的运行时 panic。
为了支持针对旧版 Go 编写的程序,可以通过设置 GODEBUG=panicnil=1
重新启用 nil panic。在编译主包位于声明 go
1.20
或更早版本的模块中的程序时,此设置会自动启用。
工具链
Go 1.21 改进了对 Go 工具链向后兼容性和向前兼容性的支持。
为了改善向后兼容性,Go 1.21 正式规范了 Go 对 GODEBUG 环境变量的使用,以控制那些根据兼容性政策不属于破坏性更改但可能导致现有程序出错的更改的默认行为。(例如,依赖于 bug 行为的程序在 bug 被修复后可能会出错,但 bug 修复不被视为破坏性更改。)当 Go 必须进行此类行为更改时,它现在会根据工作区 go.work
文件中的 go
行或者主模块 go.mod
文件中的 go
行来选择旧行为或新行为。升级到新的 Go 工具链,但将 go
行保留在其原始(旧)Go 版本,会保留旧工具链的行为。有了这种兼容性支持,最新的 Go 工具链应该始终是旧版本 Go 的最佳、最安全实现。详情请参阅“Go、向后兼容性和 GODEBUG”。
为了改善向前兼容性,Go 1.21 现在将 go.work
或 go.mod
文件中的 go
行读取为严格的最低要求:go
1.21.0
意味着该工作区或模块不能与 Go 1.20 或 Go 1.21rc1 一起使用。这使得依赖于后续 Go 版本中修复的项目可以确保它们不与早期版本一起使用。它还为使用 Go 新功能的项目提供了更好的错误报告:当问题在于需要较新版本的 Go 时,会清楚地报告该问题,而不是尝试构建代码并打印有关未解析导入或语法错误的错误。
为了更轻松地管理这些新的更严格的版本要求,go
命令现在不仅可以调用自身版本中捆绑的工具链,还可以调用在 PATH 中找到或按需下载的其他 Go 工具链版本。如果 go.mod
或 go.work
文件中的 go
行声明了对较新版本 Go 的最低要求,go
命令将自动查找并运行该版本。新的 toolchain
指令设置了一个建议使用的最低工具链版本,该版本可能比 go
严格最低版本更新。详情请参阅“Go 工具链”。
Go 命令
-pgo
build flag 现在默认为 -pgo=auto
,并且取消了在命令行上指定单个主包的限制。如果主包目录中存在名为 default.pgo
的文件,go
命令将使用它来为构建相应程序启用配置文件引导优化(PGO)。
-C
dir
flag 现在使用时必须是命令行上的第一个 flag。
新的 go
test
选项 -fullpath
会在测试日志消息中打印完整路径名,而不是仅打印基本名称。
go
test
-c
flag 现在支持为多个包编写测试二进制文件,每个文件都写入 pkg.test
,其中 pkg
是包名。如果多个正在编译的测试包具有相同的包名,则会报错。
go
test
-o
flag 现在接受一个目录参数,在这种情况下,测试二进制文件会写入该目录而不是当前目录。
使用外部 (C) 连接器并启用 cgo 时,runtime/cgo
包现在作为附加依赖项提供给 Go 连接器,以确保 Go 运行时与 C 连接器添加的任何附加库兼容。
Cgo
在 import "C"
的文件中,Go 工具链现在会正确报告在 C 类型上声明 Go 方法的错误。
运行时
当打印非常深的堆栈时,运行时现在打印最里面的 50 帧,然后是最外面的 50 帧,而不是仅打印前 100 帧。这使得更容易查看深度递归堆栈是如何开始的,对于调试堆栈溢出特别有价值。
在支持透明巨页的 Linux 平台上,Go 运行时现在更明确地管理堆的哪些部分可以使用巨页支持。这带来了更好的内存利用率:小堆使用的内存更少(病态情况下最多减少 50%),而大堆在堆的密集部分断裂的巨页更少,从而将 CPU 使用率和延迟提高最多 1%。此更改的一个后果是,运行时不再尝试解决特定的有问题 Linux 配置设置,这可能会导致更高的内存开销。建议的解决方法是根据GC 指南调整操作系统的巨页设置。但是,也有其他变通方法可用。请参阅关于 max_ptes_none
的部分。
由于运行时内部垃圾回收调优,应用程序的尾延迟可能减少高达 40%,并且内存使用量略有下降。一些应用程序也可能观察到吞吐量小幅下降。内存使用量的减少应该与吞吐量的损失成比例,这样可以通过稍微增加 GOGC
和/或 GOMEMLIMIT
来恢复先前版本的吞吐量/内存权衡(对延迟影响很小)。
在 C 中创建的线程上从 C 调用 Go 需要一些设置以准备 Go 执行。在 Unix 平台上,此设置现在在同一线程的多次调用中得以保留。这显著降低了后续 C 到 Go 调用的开销,从每次调用约 1-3 微秒降至每次调用约 100-200 纳秒。
编译器
配置文件引导优化 (PGO) 在 Go 1.20 中作为预览版添加,现在已可用于一般用途。PGO 对由生产工作负载配置文件标识为热点的代码启用额外的优化。如 Go 命令部分所述,对于主包目录中包含 default.pgo
配置文件的二进制文件,PGO 默认启用。性能提升因应用程序行为而异,代表性 Go 程序集中的大多数程序在启用 PGO 后看到了 2% 到 7% 的性能提升。详细文档请参阅 PGO 用户指南。
PGO 构建现在可以对一些接口方法调用进行去虚拟化,为最常见的被调函数添加具体调用。这使得进一步的优化成为可能,例如内联被调函数。
Go 1.21 将构建速度提高了高达 6%,这主要得益于使用 PGO 构建编译器本身。
汇编器
在 amd64 上,无帧的 nosplit 汇编函数不再自动标记为 NOFRAME
。相反,如果需要,必须显式指定 NOFRAME
属性,这与支持帧指针的其他架构上的行为相同。通过此更改,运行时现在在堆栈转换时维护帧指针。
改进了在 amd64 上进行动态链接时检查 R15
错误使用的验证器。
连接器
在 windows/amd64 上,连接器(在编译器的帮助下)现在默认发出 SEH unwinding 数据,这提高了 Go 应用程序与 Windows 调试器及其他工具的集成度。
在 Go 1.21 中,如果变量初始化器中的条目数量足够大,并且初始化器表达式没有副作用,连接器(在编译器的帮助下)现在能够删除死的(未引用的)全局 map 变量。
标准库
新增 log/slog 包
新的 log/slog 包提供了带级别的结构化日志记录。结构化日志记录发出键值对,以便快速、准确地处理大量日志数据。该包支持与流行的日志分析工具和服务集成。
新增 testing/slogtest 包
新的 testing/slogtest 包可以帮助验证 slog.Handler 的实现。
新增 slices 包
新的 slices 包提供了许多对切片的常用操作,使用可处理任何元素类型切片的泛型函数。
新增 maps 包
新的 maps 包提供了许多对 map 的常用操作,使用可处理任何键或元素类型 map 的泛型函数。
新增 cmp 包
新的 cmp 包定义了类型约束 Ordered
和两个新的泛型函数 Less
和 Compare
,它们对于有序类型很有用。
标准库的次要变化
一如既往,标准库进行了一些细微的更改和更新,这些更改和更新是在考虑到 Go 1 兼容性承诺的情况下进行的。此外还有各种性能改进,此处不再一一列举。
archive/tar
由 Header.FileInfo
返回的 io/fs.FileInfo
接口实现现在实现了 String
方法,该方法调用 io/fs.FormatFileInfo
。
archive/zip
由 FileHeader.FileInfo
返回的 io/fs.FileInfo
接口实现现在实现了 String
方法,该方法调用 io/fs.FormatFileInfo
。
由 Reader.Open
返回的 io/fs.File
的 io/fs.ReadDirFile.ReadDir
方法返回的 io/fs.DirEntry
接口实现现在实现了 String
方法,该方法调用 io/fs.FormatDirEntry
。
bytes
Buffer
类型新增了两个方法:Available
和 AvailableBuffer
。它们可以与 Write
方法一起使用,直接追加到 Buffer
中。
context
新的 WithoutCancel
函数返回一个上下文的副本,该副本在原始上下文被取消时不会被取消。
新的 WithDeadlineCause
和 WithTimeoutCause
函数提供了一种在截止时间或定时器到期时设置上下文取消原因的方法。原因可以通过 Cause
函数获取。
新的 AfterFunc
函数注册一个函数,该函数在上下文被取消后运行。
一项优化意味着调用 Background
和 TODO
并将它们转换为共享类型的结果可以被视为相等。在以前的版本中,它们总是不同的。比较 Context
值的相等性从未得到明确定义,因此这不被认为是不兼容的更改。
crypto/ecdsa
PublicKey.Equal
和 PrivateKey.Equal
现在以常量时间执行。
crypto/elliptic
所有 Curve
方法以及 GenerateKey
、Marshal
和 Unmarshal
已被弃用。对于 ECDH 操作,应使用新的 crypto/ecdh
包代替。对于更低级的操作,请使用第三方模块,例如 filippo.io/nistec。
crypto/rand
crypto/rand
包现在在 NetBSD 10.0 及更高版本上使用 getrandom
系统调用。
crypto/rsa
私有 RSA 操作(解密和签名)的性能在 GOARCH=amd64
和 GOARCH=arm64
上现在优于 Go 1.19。它在 Go 1.20 中有所退步。
由于向 PrecomputedValues
添加了私有字段,即使反序列化(例如从 JSON)先前预计算过的私钥,也必须调用 PrivateKey.Precompute
以获得最佳性能。
PublicKey.Equal
和 PrivateKey.Equal
现在以常量时间执行。
GenerateMultiPrimeKey
函数和 PrecomputedValues.CRTValues
字段已被弃用。PrecomputedValues.CRTValues
调用 PrivateKey.Precompute
时仍会填充,但在解密操作期间不会使用这些值。
crypto/sha256
当 GOARCH=amd64
且可用时,SHA-224 和 SHA-256 操作现在使用原生指令,性能提升约 3-4 倍。
crypto/tls
服务器现在跳过对已恢复连接验证客户端证书(包括不运行 Config.VerifyPeerCertificate
),但会检查过期时间。当使用客户端证书时,这会使会话票据更大。客户端在恢复时已经跳过验证,但现在即使设置了 Config.InsecureSkipVerify
也会检查过期时间。
应用程序现在可以控制会话票据的内容。
- 新的
SessionState
类型描述了一个可恢复的会话。 SessionState.Bytes
方法和ParseSessionState
函数用于序列化和反序列化SessionState
。Config.WrapSession
和Config.UnwrapSession
钩子在服务器端用于将SessionState
转换为票据以及从票据转换回SessionState
。Config.EncryptTicket
和Config.DecryptTicket
方法提供了WrapSession
和UnwrapSession
的默认实现。ClientSessionState.ResumptionState
方法和NewResumptionState
函数可供ClientSessionCache
实现使用,以在客户端存储和恢复会话。
为了减少会话票据被用作跨连接跟踪机制的可能性,服务器现在在每次恢复时都会签发新票据(如果支持且未禁用),并且票据不再包含加密它们的密钥标识符。如果向 Conn.SetSessionTicketKeys
传递大量密钥,这可能会导致明显的性能开销。
客户端和服务器现在都实现了 Extended Master Secret 扩展(RFC 7627)。ConnectionState.TLSUnique
的弃用已被撤销,现在对于支持 Extended Master Secret 的已恢复连接设置此字段。
新的 QUICConn
类型为 QUIC 实现提供支持,包括 0-RTT 支持。请注意,这本身不是一个 QUIC 实现,并且 TLS 中仍然不支持 0-RTT。
新的 VersionName
函数返回 TLS 版本号的名称。
服务器针对客户端身份验证失败发送的 TLS alert code 已得到改进。之前,这些失败总是导致“bad certificate”alert。现在,某些失败将导致更合适的 alert code,具体定义见 RFC 5246 和 RFC 8446。
- 对于 TLS 1.3 连接,如果服务器配置为使用 RequireAnyClientCert 或 RequireAndVerifyClientCert 要求客户端身份验证,并且客户端未提供任何证书,服务器现在将返回“certificate required”alert。
- 如果客户端提供的证书未由服务器上配置的受信任证书颁发机构集签名,服务器将返回“unknown certificate authority”alert。
- 如果客户端提供的证书已过期或尚未有效,服务器将返回“expired certificate”alert。
- 在所有其他与客户端身份验证失败相关的场景中,服务器仍返回“bad certificate”。
crypto/x509
RevocationList.RevokedCertificates
已被弃用,并由新的 RevokedCertificateEntries
字段取代,后者是 RevocationListEntry
类型的切片。RevocationListEntry
包含 pkix.RevokedCertificate
中的所有字段以及吊销原因码。
名称约束现在在非叶证书上正确执行,而不是在其自身证书上执行。
debug/elf
新的 File.DynValue
方法可用于检索给定动态标签列出的数值。
DT_FLAGS_1 动态标签中允许的常量标志现在定义为 DynFlag1
类型。这些标签的名称以 DF_1
开头。
该包现在定义了常量 COMPRESS_ZSTD
。
该包现在定义了常量 R_PPC64_REL24_P9NOTOC
。
debug/pe
现在尝试使用 Section.Data
或 Section.Open
返回的读取器从包含未初始化数据的节中读取会返回错误。
embed
FS.Open
返回的 io/fs.File
现在具有 ReadAt
方法,该方法实现了 io.ReaderAt
。
调用 FS.Open.Stat
将返回一个现在实现了 String
方法的类型,该方法调用 io/fs.FormatFileInfo
。
encoding/binary
新的 NativeEndian
变量可用于使用当前机器的原生字节序在字节切片和整数之间进行转换。
errors
新的 ErrUnsupported
错误提供了一种标准化方式来指示请求的操作可能因为不受支持而无法执行。例如,在使用不支持硬链接的文件系统时调用 os.Link
。
flag
新的 BoolFunc
函数和 FlagSet.BoolFunc
方法定义了一个不需要参数并在使用时调用函数的 flag。这与 Func
类似,但用于布尔 flag。
如果已对具有相同名称的 flag 调用了 Set
,则 flag 定义(通过 Bool
、BoolVar
、Int
、IntVar
等)将 panic。此更改旨在检测由于初始化顺序改变导致 flag 操作顺序与预期不同的情况。在许多情况下,此问题的解决方法是引入显式包依赖,以在任何 Set
操作之前正确排序定义。
go/ast
新的 IsGenerated
谓词报告文件语法树是否包含特殊注释,该注释通常表明文件是由工具生成的。
新的 File.GoVersion
字段记录任何 //go:build
或 // +build
指令所需的最低 Go 版本。
go/build
该包现在解析文件头(在 package
声明之前)中的构建指令(以 //go:
开头的注释)。这些指令可在新的 Package
字段 Directives
、TestDirectives
和 XTestDirectives
中获取。
go/build/constraint
新的 GoVersion
函数返回构建表达式隐含的最低 Go 版本。
go/token
新的 File.Lines
方法以与 File.SetLines
接受的形式相同的格式返回文件的行号表。
go/types
新的 Package.GoVersion
方法返回用于检查包的 Go 语言版本。
hash/maphash
hash/maphash
包现在有了纯 Go 实现,可通过 purego
build tag 进行选择。
html/template
当 JavaScript 模板字面量中出现 action 时,会返回新的错误 ErrJSTemplate
。之前返回的是一个未导出的错误。
io/fs
新的 FormatFileInfo
函数返回 FileInfo
的格式化版本。新的 FormatDirEntry
函数返回 FileInfo
的格式化版本。ReadDir
返回的 DirEntry
实现现在实现了 String
方法,该方法调用 FormatDirEntry
;传递给 WalkDirFunc
的 DirEntry
值也同样实现了 String
方法。
math/big
新的 Int.Float64
方法返回多精度整数最接近的浮点值,并指示发生的任何舍入。
net
在 Linux 上,当内核支持时,net 包现在可以使用多路径 TCP (Multipath TCP)。它默认不启用。要在客户端上使用可用的多路径 TCP,请在调用 Dialer.Dial
或 Dialer.DialContext
方法之前调用 Dialer.SetMultipathTCP
方法。要在服务器上使用可用的多路径 TCP,请在调用 ListenConfig.Listen
方法之前调用 ListenConfig.SetMultipathTCP
方法。像往常一样将网络指定为 "tcp"
、"tcp4"
或 "tcp6"
。如果内核或远程主机不支持多路径 TCP,连接将静默回退到 TCP。要测试特定连接是否正在使用多路径 TCP,请使用 TCPConn.MultipathTCP
方法。
在未来的 Go 版本中,我们可能会在支持多路径 TCP 的系统上默认启用它。
net/http
新的 ResponseController.EnableFullDuplex
方法允许服务器处理程序在写入响应的同时并发地从 HTTP/1 请求体读取。通常,HTTP/1 服务器在开始写入响应之前会自动消费任何剩余的请求体,以避免尝试在读取响应之前写入完整请求的客户端发生死锁。EnableFullDuplex
方法会禁用此行为。
当服务器以 HTTP 响应回应 HTTPS 请求时,Client
和 Transport
会返回新的 ErrSchemeMismatch
错误。
net/http 包现在支持 errors.ErrUnsupported
,这意味着表达式 errors.Is(http.ErrNotSupported, errors.ErrUnsupported)
将返回 true。
os
程序现在可以向 Chtimes
函数传递一个空的 time.Time
值,以保持访问时间或修改时间不变。
在 Windows 上,File.Chdir
方法现在会将当前目录更改为该文件所代表的目录,而不再总是返回错误。
在 Unix 系统上,如果一个非阻塞描述符被传递给 NewFile
,调用 File.Fd
方法现在将返回一个非阻塞描述符。此前,该描述符会被转换为阻塞模式。
在 Windows 上,对不存在的文件调用 Truncate
过去会创建一个空文件。现在它会返回一个指示文件不存在的错误。
在 Windows 上,调用 TempDir
现在在可用时使用 GetTempPath2W
,而不是 GetTempPathW
。新行为是一种安全强化措施,可防止以 SYSTEM 身份运行的进程创建的临时文件被非 SYSTEM 进程访问。
在 Windows 上,os 包现在支持处理那些名称以 UTF-16 存储但无法表示为有效 UTF-8 的文件。
在 Windows 上,Lstat
现在会解析以路径分隔符结尾的路径的符号链接,这与其在 POSIX 平台上的行为保持一致。
由 ReadDir
函数和 File.ReadDir
方法返回的 io/fs.DirEntry
接口的实现现在实现了一个 String
方法,该方法会调用 io/fs.FormatDirEntry
。
由 DirFS
函数返回的 io/fs.FS
接口的实现现在实现了 io/fs.ReadFileFS
和 io/fs.ReadDirFS
接口。
path/filepath
传递给 WalkDir
函数参数的 io/fs.DirEntry
接口的实现现在实现了一个 String
方法,该方法会调用 io/fs.FormatDirEntry
。
reflect
在 Go 1.21 中,ValueOf
不再强制其参数分配在堆上,允许 Value
的内容分配在栈上。对 Value
的大多数操作也允许底层值分配在栈上。
新的 Value
方法 Value.Clear
会清除映射的内容或将切片的内容置零。这与 语言中新增的 clear
内置函数相对应。
SliceHeader
和 StringHeader
类型现在已弃用。在新代码中,请优先使用 unsafe.Slice
、unsafe.SliceData
、unsafe.String
或 unsafe.StringData
。
regexp
Regexp
现在定义了 MarshalText
和 UnmarshalText
方法。它们实现了 encoding.TextMarshaler
和 encoding.TextUnmarshaler
,将被诸如 encoding/json 等包使用。
runtime
Go 程序产生的文本栈追踪,例如崩溃时、调用 runtime.Stack
或使用 debug=2
收集 goroutine profile 时产生的,现在包含栈追踪中创建每个 goroutine 的 goroutine ID。
崩溃的 Go 应用现在可以通过设置环境变量 GOTRACEBACK=wer
或在崩溃前调用 debug.SetTraceback("wer")
来选择启用 Windows 错误报告 (WER)。除了启用 WER 外,runtime 的行为将与 GOTRACEBACK=crash
相同。在非 Windows 系统上,GOTRACEBACK=wer
会被忽略。
GODEBUG=cgocheck=2
,一个彻底检查 cgo 指针传递规则的工具,不再作为 调试选项 提供。相反,它现在作为一项实验提供,使用 GOEXPERIMENT=cgocheck2
。特别需要注意的是,这意味着此模式必须在构建时选择,而不是在启动时选择。
GODEBUG=cgocheck=1
仍然可用(并且仍然是默认值)。
runtime 包中添加了一个新类型 Pinner
。Pinner
可用于“固定”Go 内存,以便非 Go 代码可以更自由地使用它。例如,现在允许将引用固定 Go 内存的 Go 值传递给 C 代码。此前,cgo 指针传递规则禁止传递任何此类嵌套引用。更多详情请参阅文档。
runtime/metrics
一些先前是内部的 GC 指标,如实时堆大小,现在可供使用。GOGC
和 GOMEMLIMIT
现在也可作为指标使用。
runtime/trace
在 amd64 和 arm64 上收集追踪现在会产生显著更小的 CPU 开销:与上一版本相比,性能提升高达 10 倍。
追踪现在包含 Go runtime 停止世界(stop-the-world)的每个原因的明确停止世界事件,而不仅仅是垃圾回收。
sync
新函数 OnceFunc
、OnceValue
和 OnceValues
捕获了 Once
的一种常见用法,用于在首次使用时延迟初始化值。
syscall
在 Windows 上,Fchdir
函数现在会将当前目录更改为其参数所代表的目录,而不再总是返回错误。
在 FreeBSD 上,SysProcAttr
有一个新字段 Jail
,可用于将新创建的进程置于 jailed 环境中。
在 Windows 上,syscall 包现在支持处理那些名称以 UTF-16 存储但无法表示为有效 UTF-8 的文件。UTF16ToString
和 UTF16FromString
函数现在在 UTF-16 数据和 WTF-8 字符串之间进行转换。这向后兼容,因为 WTF-8 是早期版本中使用的 UTF-8 格式的超集。
几个错误值现在与新的 errors.ErrUnsupported
匹配,以便 errors.Is(err, errors.ErrUnsupported)
返回 true。
ENOSYS
ENOTSUP
EOPNOTSUPP
EPLAN9
(仅限 Plan 9)ERROR_CALL_NOT_IMPLEMENTED
(仅限 Windows)ERROR_NOT_SUPPORTED
(仅限 Windows)EWINDOWS
(仅限 Windows)
testing
新增的 -test.fullpath
选项将在测试日志消息中打印完整路径名,而不是仅打印基本名称。
新函数 Testing
报告程序是否是由 go test
创建的测试。
testing/fstest
调用 Open.Stat
将返回一个现在实现了 String
方法的类型,该方法会调用 io/fs.FormatFileInfo
。
unicode
unicode
包和整个系统中相关的支持已升级到 Unicode 15.0.0。
移植
Darwin
正如 Go 1.20 版本说明中宣布的,Go 1.21 需要 macOS 10.15 Catalina 或更高版本;对先前版本的支持已终止。
Windows
正如 Go 1.20 版本说明中宣布的,Go 1.21 要求至少 Windows 10 或 Windows Server 2016;对先前版本的支持已终止。
ARM
当在非 ARM 系统上使用 GOARCH=arm
构建 Go 分发版时(即构建到 ARM 的交叉编译器时),GOARM
环境变量的默认值现在始终设置为 7
。此前,默认值取决于构建系统的特性。
当不构建交叉编译器时,默认值由检查构建系统确定。此前如此,在 Go 1.21 中仍然如此。改变的是构建交叉编译器时的行为。
WebAssembly
现在可以在 Go 程序中使用新的 go:wasmimport
指令导入来自 WebAssembly 主机的函数。
Go 调度器现在与 JavaScript 事件循环的交互效率显著提高,尤其是在频繁阻塞于异步事件的应用中。
WebAssembly 系统接口
Go 1.21 新增了对 WebAssembly System Interface (WASI) Preview 1 的实验性移植(GOOS=wasip1
, GOARCH=wasm
)。
由于新增了 GOOS
值“wasip1
”,除使用该 GOOS
值的情况外,Go 工具现在将忽略名为 *_wasip1.go
的 Go 文件。如果您有匹配该模式的现有文件名,则需要重命名它们。
ppc64/ppc64le
在 Linux 上,GOPPC64=power10
现在会生成 PC 相关指令、前缀指令和其他新的 Power10 指令。在 AIX 上,GOPPC64=power10
生成 Power10 指令,但不生成 PC 相关指令。
对于 GOPPC64=power10
GOOS=linux
GOARCH=ppc64le
,构建位置无关二进制文件时,用户在大多数情况下可以预期二进制文件大小会减小,在某些情况下会减小 3.5%。位置无关二进制文件是针对 ppc64le 使用以下 -buildmode
值构建的:c-archive
、c-shared
、shared
、pie
、plugin
。
loong64
linux/loong64
移植现在支持 -buildmode=c-archive
、-buildmode=c-shared
和 -buildmode=pie
。