Go 1.18 版本说明

Go 1.18 简介

最新的 Go 版本 1.18 是一个重要的版本,包含了对语言本身、工具链实现、运行时以及库的变更。Go 1.18 发布于 Go 1.17 七个月之后。一如既往,此版本维护了 Go 1 兼容性承诺。我们期望几乎所有 Go 程序都能像以前一样继续编译和运行。

语言变更

泛型

Go 1.18 实现了 类型参数提案 中描述的泛型特性。这包括对语言进行的重大变更——但这些变更完全向后兼容。

这些新的语言变更需要编写大量新代码,这些代码尚未在生产环境中经过充分测试。只有当更多人编写和使用泛型代码时,这种测试才会发生。我们相信该特性实现良好且质量很高。然而,与 Go 的大多数方面不同,我们无法用现实世界的经验来佐证这一信念。因此,虽然我们鼓励在适当情况下使用泛型,但在生产环境中部署泛型代码时请务必谨慎。

虽然我们相信新的语言特性设计精良且规范清晰,但我们仍可能犯错。我们想强调的是,Go 1 兼容性保证 指出:“如果需要解决规范中的不一致或不完整之处,解决该问题可能会影响现有程序的含义或合法性。我们保留解决此类问题的权利,包括更新实现。”它还指出:“如果编译器或库存在违反规范的错误,依赖于该错误行为的程序可能会因错误被修复而中断。我们保留修复此类错误的权利。”换句话说,未来版本中可能会出现使用泛型的代码在 1.18 版本中可以正常工作,但在后续版本中可能中断的情况。我们不计划或期望进行任何此类变更。然而,由于我们今天无法预见的原因,在未来版本中中断 1.18 程序可能成为必要。我们将尽可能减少此类中断,但无法保证中断为零。

以下是最显著变更的列表。更全面的概述请参阅提案。详情请参阅语言规范

  • 函数类型声明 的语法现在接受类型参数
  • 参数化的函数和类型可以通过在它们后面跟一个方括号中的类型参数列表来进行实例化。
  • 新的标记 ~ 已被添加到运算符和标点符号集合中。
  • 接口类型的语法现在允许嵌入任意类型(不仅仅是接口的类型名),以及联合类型和 ~T 类型元素。此类接口只能用作类型约束。接口现在既定义一组类型,也定义一组方法。
  • 新的预声明标识符 any 是空接口的别名。它可以用来代替 interface{}
  • 新的预声明标识符 comparable 是一个接口,表示所有可以使用 ==!= 进行比较的类型的集合。它只能用作(或嵌入)类型约束。

有三个使用泛型的实验性包可能很有用。这些包位于 x/exp 仓库中;它们的 API 不在 Go 1 保证范围内,并且随着我们获得更多的泛型使用经验,可能会发生变化。

golang.org/x/exp/constraints

适用于泛型代码的约束,例如 constraints.Ordered

golang.org/x/exp/slices

一组用于操作任意元素类型切片的泛型函数。

golang.org/x/exp/maps

一组用于操作任意键或元素类型映射的泛型函数。

当前的泛型实现存在以下已知限制:- Go 语言编译器目前无法处理泛型函数或方法内部的类型声明。我们希望在未来的版本中提供对该功能的支持。

  • Go 语言编译器不接受将类型参数类型的实参传递给内置函数 realimagcomplex。我们希望在未来的版本中移除此限制。
  • Go 语言编译器仅支持在类型参数类型 P 的值 x 上调用方法 m,条件是 m 已被 P 的约束接口显式声明。类似地,方法值 x.m 和方法表达式 P.m 也仅在 m 已被 P 显式声明时才受支持,即使 m 可能因 P 中的所有类型都实现了 m 而存在于 P 的方法集中。我们希望在未来的版本中移除此限制。
  • Go 语言编译器不支持访问类型参数类型 x 的结构体字段 x.f,即使该类型参数的类型集中的所有类型都拥有字段 f。我们可能会在未来的版本中移除此限制。
  • 不允许将类型参数或指向类型参数的指针作为未命名字段嵌入到结构体类型中。类似地,也不允许将类型参数嵌入到接口类型中。目前尚不清楚这些限制未来是否会放宽。
  • 一个包含多个项的并集元素不能拥有非空方法集的接口类型。目前尚不清楚此限制未来是否会放宽。

泛型也代表着 Go 生态系统的一个重大变化。虽然我们已经更新了几个核心工具以支持泛型,但还有更多工作要做。剩余的工具、文档和库需要时间来适应这些语言变更。

漏洞修复

Go 1.18 的编译器现在能正确报告在函数字面量内部赋值但从未使用的变量的“声明但未使用”错误。在 Go 1.18 之前,编译器在此类情况下不会报告错误。这修复了长期存在的编译器问题 #8560。此更改可能导致(可能不正确的)程序无法编译。必要的修复很简单:如果程序确实不正确则修复它,或者使用该变量,例如将其赋值给空白标识符 _。由于 go vet 总是会指出此错误,受影响的程序数量可能非常少。

Go 1.18 的编译器现在会在将如 '1' << 32 这样的 rune 常量表达式作为参数传递给内置函数 printprintln 时报告溢出错误,这与用户定义函数的行为一致。在 Go 1.18 之前,编译器在此类情况下不会报告错误,如果常量参数能放入 int64 则会静默接受。此更改可能导致(可能不正确的)程序无法编译。必要的修复很简单:如果程序确实不正确则修复它,或者显式地将有问题的参数转换为正确的类型。由于 go vet 总是会指出此错误,受影响的程序数量可能非常少。

端口支持

AMD64

Go 1.18 引入了新的 GOAMD64 环境变量,该变量在编译时选择 AMD64 架构的最低目标版本。允许的值为 v1v2v3v4。每个更高级别都需要并利用额外的处理器特性。详细描述可以在此处找到。

GOAMD64 环境变量默认为 v1

RISC-V

Linux 上的 64 位 RISC-V 架构(linux/riscv64 端口)现在支持 c-archivec-shared 构建模式。

Linux

Go 1.18 要求 Linux 内核版本为 2.6.32 或更高。

Windows

windows/armwindows/arm64 端口现在支持非协作式抢占,将此能力带到了所有四个 Windows 端口,这有望解决在调用长时间阻塞的 Win32 函数时遇到的微妙问题。

iOS

在 iOS(ios/arm64 端口)以及在基于 AMD64 的 macOS 上运行的 iOS 模拟器(ios/amd64 端口)上,Go 1.18 现在要求 iOS 12 或更高版本;对旧版本的支持已停止。

FreeBSD

Go 1.18 是支持 FreeBSD 11.x 的最后一个版本,该版本已达到生命周期终点。Go 1.19 将要求 FreeBSD 12.2+ 或 FreeBSD 13.0+。FreeBSD 13.0+ 需要设置了 COMPAT_FREEBSD12 选项的内核(这是默认设置)。

工具

模糊测试

Go 1.18 包含了模糊测试提案中描述的模糊测试实现。

请访问模糊测试着陆页开始使用。

请注意,模糊测试可能消耗大量内存,并可能在运行时影响机器的性能。另请注意,模糊测试引擎在运行时会将扩展测试覆盖率的值写入 $GOCACHE/fuzz 目录下的模糊缓存目录。目前对可写入模糊缓存的文件数量或总字节数没有限制,因此它可能占用大量存储空间(可能达到数 GB)。

Go 命令

go get {#go-get}

go get 在模块感知模式下不再构建或安装包。go get 现在专注于调整 go.mod 中的依赖项。实际上,-d 标志始终启用。要在当前模块上下文之外安装可执行文件的最新版本,请使用 go install example.com/cmd@latest。可以使用任何版本查询来代替 latest。这种形式的 go install 是在 Go 1.16 中添加的,因此支持旧版本的项目可能需要同时提供 go installgo get 的安装说明。go get 现在在模块外部使用时会报告错误,因为没有 go.mod 文件可供更新。在 GOPATH 模式下(GO111MODULE=off),go get 仍像以前一样构建和安装包。

自动 go.modgo.sum 更新

go mod graphgo mod vendorgo mod verifygo mod why 子命令不再自动更新 go.modgo.sum 文件。 (可以使用 go getgo mod tidygo mod download 显式更新这些文件。)

go version

go 命令现在将版本控制信息嵌入到二进制文件中。它包括当前签出的修订版本、提交时间以及一个指示是否存在已编辑或未跟踪文件的标志。如果在 Git、Mercurial、Fossil 或 Bazaar 仓库内的目录中调用 go 命令,并且 main 包及其所在的主模块位于同一仓库中,则会嵌入版本控制信息。可以使用标志 -buildvcs=false 来省略此信息。

此外,go 命令还嵌入了关于构建的信息,包括构建和工具标签(通过 -tags 设置)、编译器、汇编器和链接器标志(如 -gcflags)、是否启用了 cgo 以及(如果启用了)cgo 环境变量的值(如 CGO_CFLAGS)。 版本控制信息和构建信息都可以与模块信息一起通过 go version -m fileruntime/debug.ReadBuildInfo(用于当前正在运行的二进制文件)或新的 debug/buildinfo 包来读取。

嵌入式构建信息的底层数据格式可能会随新的 Go 版本而更改,因此旧版本的 go 可能无法处理由新版本 go 生成的构建信息。 要读取由 go 1.18 构建的二进制文件的版本信息,请使用 go 1.18+ 中的 go version 命令和 debug/buildinfo 包。

go mod download

如果主模块的 go.mod 文件指定了 go 1.17 或更高版本,那么不带参数的 go mod download 现在只下载主模块 go.mod 文件中显式要求的模块的源代码。(在 go 1.17 或更高版本的模块中,该集合已经包含了构建主模块中的包和测试所需的所有依赖项。) 要同时下载传递依赖项的源代码,请使用 go mod download all

go mod vendor

go mod vendor 子命令现在支持 -o 标志来设置输出目录。 (其他 go 命令在使用 -mod=vendor 加载包时,仍然从模块根目录的 vendor 目录读取,因此此标志的主要用途是针对需要收集包源代码的第三方工具。)

go mod tidy

go mod tidy 命令现在在 go.sum 文件中保留额外的校验和,这些校验和对应的模块的源代码被用于验证每个导入的包是否由构建列表中的唯一一个模块提供。因为这种情况很少见,并且如果不应用此规则会导致构建错误,所以此更改_不_取决于主模块 go.mod 文件中的 go 版本。

go work

go 命令现在支持"工作区"模式。如果在工作目录或父目录中找到 go.work 文件,或者通过 GOWORK 环境变量指定了一个,它将使 go 命令进入工作区模式。 在工作区模式下,go.work 文件将用于确定用作模块解析根的主模块集合,而不是使用通常找到的 go.mod 文件来指定单个主模块。更多信息请参阅 go work 文档。

go build -asan

go build 命令及相关命令现在支持 -asan 标志,该标志启用与使用地址消毒器(C 编译器选项 -fsanitize=address)编译的 C(或 C++)代码的互操作。

go test

go 命令现在支持用于上述新的模糊测试支持的附加命令行选项:

  • go test 支持 -fuzz-fuzztime-fuzzminimizetime 选项。 有关这些选项的文档,请参阅 go help testflag
  • go clean 支持 -fuzzcache 选项。 有关文档,请参阅 go help clean

//go:build

Go 1.17 引入了 //go:build 行作为编写构建约束的更可读方式,以替代 // +build 行。 从 Go 1.17 开始,gofmt 会添加 //go:build 行以匹配现有的 +build 行并保持它们同步,而 go vet 会在它们不同步时进行诊断。由于 Go 1.18 的发布标志着 Go 1.16 停止支持, 所有受支持的 Go 版本现在都能理解 //go:build 行。 在 Go 1.18 中,go fix 现在会删除那些在其 go.mod 文件中声明 go 1.18 或更高版本的模块中已过时的 // +build 行。

更多信息请参阅 go.dev/design/draft-gobuild

Gofmt

gofmt 现在会并发地读取和格式化输入文件, 其内存限制与 GOMAXPROCS 成正比。 在拥有多颗 CPU 的机器上,gofmt 现在应该明显更快。

Vet

针对泛型的更新

vet 工具已更新以支持泛型代码。 在大多数情况下,如果对泛型代码进行类型参数替换(用其 类型集合 中的某个类型)后得到的等价非泛型代码会报告错误, 那么它也会在泛型代码中报告相同的错误。 例如,vet 会在以下代码中报告格式错误:

func Print[T ~int|~string](t T) {
    fmt.Printf("%d", t)
}

因为它会在 Print[string] 的非泛型等价代码中报告格式错误:

func PrintString(x string) {
    fmt.Printf("%d", x)
}

现有检查器的精度改进

cmd/vet 中的检查器 copylockprintfsortslicetestinggoroutinetests 都进行了适度的精度改进,以处理更多的代码模式。 这可能会导致现有包中出现新报告的错误。例如,printf 检查器现在会跟踪通过拼接字符串常量创建的格式化字符串。 因此,vet 会在以下代码中报告错误:

  // fmt.Printf formatting directive %d is being passed to Println.
  fmt.Println("%d"+` ≡ x (mod 2)`+"\n", x%2)

Runtime

垃圾回收器现在在决定运行频率时,会包含非堆来源的垃圾回收器工作量(例如,栈扫描)。 因此,当这些来源的工作量显著时,垃圾回收器的开销变得更加可预测。 对于大多数应用程序,这些变化将是微不足道的;然而, 一些 Go 应用程序现在可能比以前使用更少的内存并花更多时间进行垃圾回收,或者反之亦然。 预期的解决方法是根据需要调整 GOGC

运行时现在更高效地将内存归还给操作系统, 并且经过调优,能更积极地执行此操作。

Go 1.17 总体上改进了栈跟踪中参数的格式, 但对于通过寄存器传递的参数可能会打印不准确的值。 Go 1.18 通过在每个可能不准确的值后面打印一个问号 (?) 来改进这一点。

内置函数 append 现在在决定何时需要分配新的底层数组并扩展 slice 时,使用了一个略有不同的公式。 新公式更不容易出现分配行为的突然变化。

Compiler

Go 1.17 在特定操作系统上的 64 位 x86 架构上 实现了一种使用寄存器而非栈来传递函数参数和结果的新方法。 Go 1.18 将支持的平台扩展到包括 64 位 ARM (GOARCH=arm64)、 大端和小端 64 位 PowerPC (GOARCH=ppc64, ppc64le) 以及所有操作系统上的 64 位 x86 架构 (GOARCH=amd64)。 在 64 位 ARM 和 64 位 PowerPC 系统上,基准测试显示 典型性能提升 10% 或更高。

正如 Go 1.17 发布说明中 提到的, 此更改不影响任何安全 Go 代码的功能,并且设计为对大多数汇编代码没有影响。 详情请参阅 Go 1.17 发布说明

编译器现在可以内联包含 range 循环或带标签的 for 循环的函数。

新的 -asan 编译器选项支持新的 go 命令 -asan 选项。

由于编译器的类型检查器被完全替换以支持泛型, 一些错误消息现在使用的措辞可能与以前不同。 在某些情况下,Go 1.18 之前的错误消息提供了更多细节或表述得更有帮助。 我们计划在 Go 1.19 中解决这些情况。

由于与支持泛型相关的编译器更改, Go 1.18 的编译速度可能比 Go 1.17 的编译速度慢大约 15%。 已编译代码的执行时间不受影响。我们计划在未来的版本中提高编译器的速度。

Linker

链接器现在发出的 重定位项 大大减少。 因此,大多数代码库链接速度更快,链接所需内存更少,并且生成的二进制文件更小。 处理 Go 二进制文件的工具应使用 Go 1.18 的 debug/gosym 包 来透明地处理新旧二进制文件。

新的 -asan 链接器选项支持新的 go 命令 -asan 选项。

Bootstrap

当从源代码构建 Go 发行版且未设置 GOROOT_BOOTSTRAP 时, 以前版本的 Go 会在目录 $HOME/go1.4 (Windows 上为 %HOMEDRIVE%%HOMEPATH%\go1.4) 中查找 Go 1.4 或更高版本的引导工具链。 Go 现在首先查找 $HOME/go1.17$HOME/sdk/go1.17, 然后再回退到 $HOME/go1.4。 我们计划让 Go 1.19 要求使用 Go 1.17 或更高版本进行引导, 此更改应该能使过渡更加顺畅。 更多详情请参阅 go.dev/issue/44505

Standard library

新增 debug/buildinfo 包 {#debug_buildinfo}

新增的 debug/buildinfo 包提供了访问 go 命令构建的可执行文件中嵌入的模块版本、版本控制信息和构建标志的功能。 当前运行的二进制文件也可以通过 runtime/debug.ReadBuildInfo 获取相同信息,还可以在命令行使用 go version -m 查看。

新增 net/netip

新增的 net/netip 包定义了一种新的 IP 地址类型 Addr。 与现有的 net.IP 类型相比,netip.Addr 类型占用内存更少,是不可变的,并且可比较,因此支持 == 操作符,并可作为映射键使用。

除了 Addr,该包还定义了 AddrPort(表示 IP 地址和端口)和 Prefix(表示网络 CIDR 前缀)。

该包还定义了若干函数来创建和检查这些新类型: AddrFrom4AddrFrom16AddrFromSliceAddrPortFromIPv4UnspecifiedIPv6LinkLocalAllNodesIPv6UnspecifiedMustParseAddrMustParseAddrPortMustParsePrefixParseAddrParseAddrPortParsePrefixPrefixFrom

net 包包含与现有方法并行的新方法,但返回 netip.AddrPort,而不是更重量级的 net.IP*net.UDPAddr 类型: Resolver.LookupNetIPUDPConn.ReadFromUDPAddrPortUDPConn.ReadMsgUDPAddrPortUDPConn.WriteToUDPAddrPortUDPConn.WriteMsgUDPAddrPort。 新增的 UDPConn 方法支持无内存分配的 I/O 操作。

net 包现在还包含用于在现有的 TCPAddr/UDPAddr 类型与 netip.AddrPort 之间进行转换的函数和方法: TCPAddrFromAddrPortUDPAddrFromAddrPortTCPAddr.AddrPortUDPAddr.AddrPort

客户端默认禁用 TLS 1.0 和 1.1

如果未设置 Config.MinVersion,客户端连接现在默认使用 TLS 1.2。任何安全的现代服务器都应支持 TLS 1.2,浏览器自 2020 年起已要求支持。仍然可以通过将 Config.MinVersion 设置为 VersionTLS10 来支持 TLS 1.0 和 1.1。 服务器端默认值保持不变,仍为 TLS 1.0。

可以通过设置环境变量 GODEBUG=tls10default=1 临时将默认值回退到 TLS 1.0。 此选项将在 Go 1.19 中移除。

拒绝 SHA-1 证书

crypto/x509 现在将拒绝使用 SHA-1 哈希函数签名的证书。这不适用于自签名的根证书。针对 SHA-1 的实际攻击 自 2017 年以来已被证实,受公众信任的证书颁发机构自 2015 年起不再签发 SHA-1 证书。

可以通过设置环境变量 GODEBUG=x509sha1=1 临时回退此行为。 此选项将在未来的版本中移除。

标准库的微小变更

一如既往,库中包含了各种微小变更和更新,这些变更均遵循 Go 1 兼容性承诺

bufio

新增的 Writer.AvailableBuffer 方法返回一个容量可能非空的空缓冲区,可用于类似追加的 API。追加数据后,该缓冲区可提供给后续的 Write 调用,并可能避免任何复制操作。

当在缓冲区为 nil 的对象上调用时,Reader.ResetWriter.Reset 方法现在使用默认缓冲区大小。

bytes

新增的 Cut 函数围绕分隔符切分 []byte。它可以替代并简化 IndexIndexByteIndexRuneSplitN 的许多常见用法。

TrimTrimLeftTrimRight 现在是零内存分配的,特别是对于小型 ASCII 字符集,速度提高了多达 10 倍。

Title 函数现已弃用。它不处理 Unicode 标点符号和特定于语言的大写规则,并已被 golang.org/x/text/cases 包取代。

crypto/elliptic

P224P384P521 曲线实现现在都由 addchainfiat-crypto 项目生成的代码提供支持,后者基于算术运算的形式验证模型。它们现在使用更安全的完备公式和内部 API。P-224 和 P-384 的性能现在大约提升了四倍。所有特定曲线的实现现在都是恒定时间的。

操作无效的曲线点(即 IsOnCurve 方法返回 false 的点,且这些点永远不会被 Unmarshal 或作用于有效点的 Curve 方法返回)一直以来都是未定义行为,可能导致密钥恢复攻击,并且现在不被新后端支持。如果向 P224P384P521 方法提供了无效点,该方法现在将返回一个随机点。在未来版本中,此行为可能会变为显式恐慌。

crypto/tls

新增的 Conn.NetConn 方法允许访问底层的 net.Conn

crypto/x509

当以 nil 值的 VerifyOpts.Roots 调用,或使用从 SystemCertPool 返回的根证书池时,Certificate.Verify 现在在 macOS 和 iOS 上使用平台 API 来验证证书有效性。

SystemCertPool 现在在 Windows 上可用。

在 Windows、macOS 和 iOS 上,当由 SystemCertPool 返回的 CertPool 被添加了额外的证书时,Certificate.Verify 将进行两次验证:一次使用平台验证器 API 和系统根证书,另一次使用 Go 验证器和额外的根证书。平台验证器 API 返回的证书链将被优先使用。

CertPool.Subjects 已弃用。在 Windows、macOS 和 iOS 上,由 SystemCertPool 返回的 CertPoolSubjects 返回的切片中将不包含系统根证书,因为静态列表无法适当地表示平台策略,而且可能根本无法从平台 API 获取。

在 Go 1.19 中,可能会移除对使用依赖 MD5 哈希的签名算法(MD5WithRSA)签署证书的支持。

debug/dwarf

StructFieldBasicType 结构体现在都有一个 DataBitOffset 字段,如果存在 DW_AT_data_bit_offset 属性,则该字段保存其值。

debug/elf

新增了 R_PPC64_RELATIVE 常量。

debug/plan9obj

File.Symbols 方法现在在文件没有符号节时,会返回新的导出错误值 ErrNoSymbols

embed

go:embed 指令现在可以以 all: 开头,以包含文件名以点或下划线开头的文件。

go/ast

根据提案 Additions to go/ast and go/token to support parameterized functions and types,对 go/ast 包进行了以下扩充:

  • FuncTypeTypeSpec 节点有一个新字段 TypeParams,用于保存类型参数(如果有)。
  • 新的表达式节点 IndexListExpr 表示带有多个索引的索引表达式,用于函数和类型实例化时带有多个显式类型参数的情况。

go/constant

新的 Kind.String 方法返回接收者 kind 的人类可读名称。

go/token

新的常量 TILDE 表示 ~ 令牌,符合提案 Additions to go/ast and go/token to support parameterized functions and types

go/types

新的 Config.GoVersion 字段设置所接受的 Go 语言版本。

根据提案 Additions to go/types to support type parameters,对 go/types 包进行了以下扩充:- 新增了表示类型参数的类型 TypeParam、工厂函数 NewTypeParam 及其相关方法。

谓词 AssignableToConvertibleToImplementsIdenticalIdenticalIgnoreTagsAssertableTo 现在也可以处理是或包含广义接口的参数,即在 Go 代码中只能用作类型约束的接口。 请注意,AssignableToConvertibleToImplementsAssertableTo 对于未实例化的泛型类型作为参数时行为是未定义的,并且如果第一个参数是广义接口,AssertableTo 的行为也是未定义的。

html/template

range 管道中,新增的 {{break}} 命令将提前结束循环,而新增的 {{continue}} 命令将立即开始下一次循环迭代。

and 函数不再总是计算所有参数;它会在第一个计算结果为 false 的参数后停止计算参数。类似地,or 函数现在会在第一个计算结果为 true 的参数后停止计算参数。如果任何参数是函数调用,这会产生区别。

image/draw

DrawDrawMask 的回退实现(当参数不是最常见的图像类型时使用)现在在这些参数实现了 Go 1.17 中添加的可选接口 draw.RGBA64Imageimage.RGBA64Image 时会更快。

net

net.Error.Temporary 已被弃用。

net/http

在 WebAssembly 目标上,Transport 中的 DialDialContextDialTLSDialTLSContext 方法字段(如果已指定)现在将被正确用于发起 HTTP 请求。

新增的 Cookie.Valid 方法报告 cookie 是否有效。

新增的 MaxBytesHandler 函数创建一个 Handler,它使用 MaxBytesReader 包装其 ResponseWriterRequest.Body

在查找包含非 ASCII 字符的域名时,Unicode 到 ASCII 的转换现在按照 Unicode IDNA 兼容性处理 标准 (UTS #46) 中定义的非过渡处理 (Nontransitional Processing) 来完成。四个不同字符的解释方式已更改:ß、ς、零宽度连接符 U+200D 和零宽度非连接符 U+200C。非过渡处理与大多数应用程序和 Web 浏览器保持一致。

os/user

当 cgo 不可用时,User.GroupIds 现在使用 Go 的原生实现。

reflect

新增了 Value.SetIterKeyValue.SetIterValue 方法,它们使用映射迭代器作为源来设置 Value。它们等价于 Value.Set(iter.Key())Value.Set(iter.Value()), 但分配次数更少。

新增了 Value.UnsafePointer 方法,它将 Value 的值作为 unsafe.Pointer 返回。这允许调用者从 Value.UnsafeAddrValue.Pointer 迁移,从而消除在调用点执行 uintptrunsafe.Pointer 转换的需要(如 unsafe.Pointer 规则所要求)。

新增了 MapIter.Reset 方法,它将接收者更改为迭代一个不同的映射。使用 MapIter.Reset 可以实现对多个映射的无分配迭代。

已向 Value 添加了多个方法 ( Value.CanIntValue.CanUintValue.CanFloatValue.CanComplex ),用于测试转换是否安全。

新增了 Value.FieldByIndexErr,以避免在 Value.FieldByIndex 中通过指向嵌入结构体的 nil 指针逐步访问时发生的 panic。

reflect.Ptrreflect.PtrTo 已分别重命名为 reflect.Pointerreflect.PointerTo,以便与 reflect 包的其余部分保持一致。旧名称将继续可用,但将在未来的 Go 版本中被弃用。

regexp

regexp 现在将 UTF-8 字符串中的每个无效字节视为 U+FFFD

runtime/debug

BuildInfo 结构体有两个新字段,包含有关二进制文件构建方式的附加信息:

runtime/pprof

CPU 分析器现在在 Linux 上使用每线程计时器。这提高了分析器可观测的最大 CPU 使用率,并减少了某些形式的偏差。

strconv

strconv.Unquote 现在拒绝 Unicode 代理项半区字符。

strings

新增了 Cut 函数,它围绕分隔符切割 string。它可以替代并简化 IndexIndexByteIndexRuneSplitN 的许多常见用法。

新增了 Clone 函数,它复制输入 string,而返回的克隆 string 不会引用输入字符串的内存。

TrimTrimLeftTrimRight 现在是无分配的,并且对于小型 ASCII 字符集,速度最多可提高 10 倍。

Title 函数现已弃用。它不处理 Unicode 标点符号和特定语言的大小写规则,并已被 golang.org/x/text/cases 包取代。

sync

新增了方法 Mutex.TryLockRWMutex.TryLockRWMutex.TryRLock,如果锁当前未被持有,它们将获取该锁。

syscall

为 Windows 引入了新函数 SyscallN,允许使用任意数量的参数进行调用。因此, SyscallSyscall6Syscall9Syscall12Syscall15Syscall18 已弃用,推荐使用 SyscallN

SysProcAttr.Pdeathsig 现在在 FreeBSD 中受支持。

syscall/js

Wrapper 接口已被移除。

testing

-run-bench 参数中 / 的优先级已提高。以前 A/B|C/D 会被视为 A/(B|C)/D,现在被视为 (A/B)|(C/D)

如果 -run 选项未选择任何测试,则 -count 选项将被忽略。在不太可能的情况下,如果测试每次运行时更改了要运行的子测试集,这可能会改变现有测试的行为。 新的 testing.F 类型 被用于新的上文描述的模糊测试支持。测试现在也支持命令行选项 -test.fuzz-test.fuzztime-test.fuzzminimizetime

text/template

range 管道内,新的 {{break}} 命令将提前结束循环,而新的 {{continue}} 命令将立即开始下一次循环迭代。

and 函数不再总是计算所有参数;它会在遇到第一个计算结果为 false 的参数后停止计算。类似地,or 函数现在会在遇到第一个计算结果为 true 的参数后停止计算。如果任何参数是函数调用,这会产生差异。

text/template/parse

该包通过新的常量 NodeBreak 和新的类型 BreakNode 支持新的 text/templatehtml/template {{break}} 命令,并且通过新的常量 NodeContinue 和新的类型 ContinueNode 支持新的 {{continue}} 命令。

unicode/utf8

新的 AppendRune 函数将一个 rune 的 UTF-8 编码追加到 []byte 切片。