Go 1.14 发行说明

Go 1.14 简介

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

go 命令中的模块支持现已准备好投入生产使用,我们鼓励所有用户迁移到 Go 模块进行依赖管理。如果您由于 Go 工具链中的问题而无法迁移,请确保已提交开放问题。(如果问题不在 Go1.15 里程碑中,请告知我们它为何阻止您迁移,以便我们进行适当的优先级排序。)

语言变化

根据重叠接口提案,Go 1.14 现在允许嵌入具有重叠方法集的接口:来自嵌入接口的方法可能与(嵌入)接口中已存在的方法具有相同的名称和相同的签名。这解决了通常(但不限于)发生在菱形嵌入图中的问题。接口中显式声明的方法必须像以前一样保持唯一

移植

Darwin

Go 1.14 是最后一个在 macOS 10.11 El Capitan 上运行的版本。Go 1.15 将需要 macOS 10.12 Sierra 或更高版本。

Go 1.14 是最后一个支持 macOS 上 32 位二进制文件(darwin/386 端口)的 Go 版本。从 macOS 10.15 (Catalina) 开始,macOS 不再支持它们。Go 继续支持 64 位 darwin/amd64 端口。

Go 1.14 可能是最后一个支持 iOS、iPadOS、watchOS 和 tvOS(darwin/arm 端口)上 32 位二进制文件的 Go 版本。Go 继续支持 64 位 darwin/arm64 端口。

Windows

Windows 上的 Go 二进制文件现在已启用 DEP(数据执行保护)

在 Windows 上,如果权限参数中未设置位 0o200(所有者写入权限),则通过 os.OpenFile 使用 os.O_CREATE 标志或通过 syscall.Open 使用 syscall.O_CREAT 标志创建文件现在将以只读方式创建文件。这使得 Windows 上的行为更像 Unix 系统上的行为。

WebAssembly

现在可以通过垃圾回收机制回收通过 js.Value 对象从 Go 引用 JavaScript 值。

js.Value 值不再可以使用 == 运算符进行比较,而必须使用它们的 Equal 方法进行比较。

js.Value 现在具有 IsUndefinedIsNullIsNaN 方法。

RISC-V

Go 1.14 包含对 Linux 上 64 位 RISC-V 的实验性支持(GOOS=linux, GOARCH=riscv64)。请注意,性能、汇编语法稳定性以及可能的正确性仍在开发中。

FreeBSD

Go 现在支持 FreeBSD 12.0 或更高版本上的 64 位 ARM 架构(freebsd/arm64 端口)。

Native Client (NaCl)

如 Go 1.13 发行说明中宣布的那样,Go 1.14 放弃了对 Native Client 平台(GOOS=nacl)的支持。

Illumos

运行时现在为 runtime.NumCPUGOMAXPROCS 的默认值遵守区域 CPU 上限(zone.cpu-cap 资源控制)。

工具

Go 命令

Vendoring(供应商化)

当主模块包含顶级 vendor 目录且其 go.mod 文件指定 go 1.14 或更高版本时,go 命令现在对接受该标志的操作默认使用 -mod=vendor。该标志的新值 -mod=mod 会使 go 命令从模块缓存加载模块(就像没有 vendor 目录一样)。

当设置了 -mod=vendor(显式或默认)时,go 命令现在会验证主模块的 vendor/modules.txt 文件与其 go.mod 文件是否一致。

go list -m 不再静默省略 vendor 目录中不提供包的传递依赖项。如果设置了 -mod=vendor 并且请求的信息未在 vendor/modules.txt 中提及,它现在会显式失败。

标志

go get 命令不再接受 -mod 标志。以前,该标志的设置要么被忽略,要么导致构建失败

go.mod 文件是只读且不存在顶级 vendor 目录时,-mod=readonly 现在默认设置。

-modcacherw 是一个新标志,指示 go 命令将模块缓存中新创建的目录保留其默认权限,而不是将其设置为只读。使用此标志会使测试或其他工具更有可能意外添加未包含在模块已验证校验和中的文件。但是,它允许使用 rm -rf(而不是 go clean -modcache)来删除模块缓存。

-modfile=file 是一个新标志,指示 go 命令读取(并可能写入)替代的 go.mod 文件,而不是模块根目录中的文件。名为 go.mod 的文件仍必须存在才能确定模块根目录,但不会访问它。指定 -modfile 时,还会使用替代的 go.sum 文件:其路径是通过从 -modfile 标志中截断 .mod 扩展名并追加 .sum 派生的。

环境变量

GOINSECURE 是一个新环境变量,指示 go 命令在直接从其来源获取某些模块时,不要求 HTTPS 连接并跳过证书验证。与现有 GOPRIVATE 变量一样,GOINSECURE 的值是逗号分隔的 glob 模式列表。

模块外的命令

当显式启用模块感知模式(通过设置 GO111MODULE=on)时,如果没有 go.mod 文件,大多数模块命令的功能会受到更多限制。例如,go buildgo run 和其他构建命令只能构建标准库中的包以及命令行上指定为 .go 文件的包。

以前,go 命令会将每个包路径解析为模块的最新版本,但不会记录模块路径或版本。这导致了缓慢、不可重现的构建

go get 继续像以前一样工作,go mod download 和带有显式版本的 go list -m 也是如此。

+incompatible 版本

如果模块的最新版本包含 go.mod 文件,除非明确请求或已要求,否则 go get 将不再升级到该模块的不兼容主要版本。go list 在直接从版本控制获取此类模块时也省略了不兼容的主要版本,但如果代理报告,则可能包含它们。

go.mod 文件维护

除了 go mod tidy 之外的 go 命令不再删除指定主模块的其他(传递)依赖项已隐含的间接依赖项版本的 require 指令。

除了 go mod tidy 之外的 go 命令不再编辑 go.mod 文件,如果更改仅是装饰性的。

当设置了 -mod=readonly 时,go 命令将不再因缺少 go 指令或错误的 // indirect 注释而失败。

模块下载

go 命令现在在模块模式下支持 Subversion 存储库。

go 命令现在包含来自模块代理和其他 HTTP 服务器的纯文本错误消息片段。只有当错误消息是有效的 UTF-8 且仅包含图形字符和空格时,才会显示它。

测试

go test -v 现在会在 t.Log 输出发生时流式传输,而不是在所有测试结束时。

运行时

此版本改进了 defer 的大多数用例的性能,使其与直接调用延迟函数相比,几乎没有开销。因此,defer 现在可以在对性能敏感的代码中使用,而无需担心开销。

Goroutines 现在可以异步抢占。因此,不带函数调用的循环不再可能使调度程序死锁或显着延迟垃圾回收。这在所有平台(windows/armdarwin/armjs/wasmplan9/* 除外)上都受支持。

抢占实现的一个结果是,在 Unix 系统(包括 Linux 和 macOS 系统)上,使用 Go 1.14 构建的程序将比使用早期版本构建的程序收到更多信号。这意味着使用 syscallgolang.org/x/sys/unix 等包的程序将看到更多慢速系统调用失败并出现 EINTR 错误。这些程序必须以某种方式处理这些错误,最可能是循环以再次尝试系统调用。有关此内容的更多信息,请参阅 Linux 系统的 man 7 signal 或其他系统的类似文档。

页分配器效率更高,并且在 GOMAXPROCS 值较高时,锁竞争显着减少。这在并行且高速进行的大量分配中表现为较低的延迟和较高的吞吐量。

内部计时器(由 time.Aftertime.Ticknet.Conn.SetDeadline 等使用)效率更高,锁竞争更少,上下文切换更少。这是一项性能改进,不应导致任何用户可见的更改。

编译器

此版本添加了 -d=checkptr 作为编译时选项,用于添加检测以动态检查 Go 代码是否遵循 unsafe.Pointer 安全规则。此选项默认启用(Windows 除外),带有 -race-msan 标志,并可以通过 -gcflags=all=-d=checkptr=0 禁用。具体来说,-d=checkptr 检查以下内容

  1. unsafe.Pointer 转换为 *T 时,结果指针必须为 T 适当地对齐。
  2. 如果指针算术的结果指向 Go 堆对象,则其中一个 unsafe.Pointer 类型的操作数必须指向同一对象。

目前不建议在 Windows 上使用 -d=checkptr,因为它会在标准库中导致误报。

编译器现在可以使用 -json 标志输出关键优化的机器可读日志,包括内联、逃逸分析、边界检查消除和 nil 检查消除。

详细的逃逸分析诊断(-m=2)现在再次生效。这已从上一个版本中新的逃逸分析实现中删除。

macOS 二进制文件中的所有 Go 符号现在都以一个下划线开头,遵循平台约定。

此版本包含对编译器插入覆盖率检测以进行模糊测试的实验性支持。有关更多详细信息,请参阅问题 14565。此 API 可能会在未来版本中更改。

边界检查消除现在使用来自切片创建的信息,并且可以消除类型小于 int 的索引的检查。

标准库

新字节序列哈希包

Go 1.14 包含一个新包 hash/maphash,它提供字节序列上的哈希函数。这些哈希函数旨在用于实现哈希表或其他需要将任意字符串或字节序列映射到无符号 64 位整数上的均匀分布的数据结构。

哈希函数是抗碰撞的,但不是加密安全的。

给定字节序列的哈希值在单个进程中是一致的,但在不同进程中将是不同的。

对库的微小更改

与往常一样,库中有各种微小的更改和更新,这些都是在遵守 Go 1 兼容性承诺的前提下进行的。

crypto/tls

已移除对 SSL 3.0 版本 (SSLv3) 的支持。请注意,SSLv3 是早于 TLS 的加密损坏协议。

TLS 1.3 不能再通过 GODEBUG 环境变量禁用。使用 Config.MaxVersion 字段配置 TLS 版本。

当通过 Config.Certificates 字段提供多个证书链时,现在会自动选择与对等方兼容的第一个证书链。这允许例如提供 ECDSA 和 RSA 证书,并让包自动选择最佳证书。请注意,如果未设置 Certificate.Leaf 字段,则此选择的性能会很差。Config.NameToCertificate 字段仅支持将单个证书与给定名称关联,现在已弃用,应将其保留为 nil。类似地,Config.BuildNameToCertificate 方法(它从叶证书构建 NameToCertificate 字段)现在已弃用,不应调用。

新的 CipherSuitesInsecureCipherSuites 函数返回当前已实现的密码套件列表。新的 CipherSuiteName 函数返回密码套件 ID 的名称。

新的 (*ClientHelloInfo).SupportsCertificate (*CertificateRequestInfo).SupportsCertificate 方法公开对等方是否支持某个证书。

tls 包不再支持旧版下一协议协商 (NPN) 扩展,现在只支持 ALPN。在以前的版本中,它两者都支持。没有 API 更改,应用程序应该像以前一样运行。大多数其他客户端和服务器已经删除了 NPN 支持,转而支持标准化的 ALPN。

在 TLS 1.2 握手中,当支持时现在使用 RSA-PSS 签名。这不会影响大多数应用程序,但不支持 RSA-PSS 签名的自定义 Certificate.PrivateKey 实现将需要使用新的 Certificate.SupportedSignatureAlgorithms 字段来禁用它们。

如果设置了 Config.GetConfigForClient,则 Config.CertificatesCertificateRequestInfo.Version 字段为客户端证书回调提供 TLS 版本。

新的 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 常量使用之前称为 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 的密码套件的最终名称。

crypto/x509

Certificate.CreateCRL 现在支持 Ed25519 颁发者。

debug/dwarf

debug/dwarf 包现在支持读取 DWARF 版本 5。

新方法 (*Data).AddSection 支持将输入文件中的任意新 DWARF 节添加到 DWARF Data 中。

新方法 (*Reader).ByteOrder 返回当前编译单元的字节序。这可以用于解释以本机顺序编码的属性,例如位置描述。

新方法 (*LineReader).Files 从行读取器返回文件名表。这可以用于解释 DWARF 属性(如 AttrDeclFile)的值。

encoding/asn1

Unmarshal 现在支持 ASN.1 字符串类型 BMPString,由新的 TagBMPString 常量表示。

encoding/json

Decoder 类型支持一个新方法 InputOffset,它返回当前解码器位置的输入流字节偏移量。

Compact 不再转义 U+2028U+2029 字符,这从来都不是一个文档化的功能。要进行正确的转义,请参阅 HTMLEscape

Number 不再接受无效数字,以更紧密地遵循文档化行为。如果程序需要接受空字符串等无效数字,请考虑使用 Unmarshaler 包装该类型。

Unmarshal 现在可以支持具有实现 encoding.TextUnmarshaler 的底层字符串类型的映射键。

go/build

Context 类型有一个新字段 Dir,可用于设置构建的工作目录。默认值是运行进程的当前目录。在模块模式下,这用于查找主模块。

go/doc

新函数 NewFromFiles*ast.File 列表计算包文档,并将示例与适当的包元素关联。新信息在 PackageTypeFunc 类型的新 Examples 字段以及 Example 类型的新 Suffix 字段中可用。

io/ioutil

TempDir 现在可以创建名称具有可预测前缀和后缀的目录。与 TempFile 一样,如果模式包含“*”,则随机字符串替换最后一个“*”。

log

新标志 Lmsgprefix 可用于告知日志函数在日志消息之前而不是在行开头立即发出可选的输出前缀。

math

新函数 FMA 在浮点数中计算 x*y+z,而没有对 x*y 计算进行中间舍入。一些架构使用专用硬件指令实现此计算,以提高性能。

math/big

GCD 方法现在允许输入 ab 为零或负数。

math/bits

新函数 RemRem32Rem64 支持即使商溢出也能计算余数。

mime

.js.mjs 文件的默认类型现在是 text/javascript 而不是 application/javascript。这符合 IETF 草案,该草案将 application/javascript 视为已过时。

mime/multipart

新的 Reader 方法 NextRawPart 支持获取下一个 MIME 部分,而无需透明地解码 quoted-printable 数据。

net/http

新的 Header 方法 Values 可用于获取与规范化键关联的所有值。

新的 Transport 字段 DialTLSContext 可用于指定用于为非代理 HTTPS 请求创建 TLS 连接的可选拨号函数。此新字段可以代替 DialTLS 使用,后者现在被视为已弃用;DialTLS 将继续工作,但新代码应使用 DialTLSContext,它允许传输在不再需要拨号时立即取消拨号。

在 Windows 上,ServeFile 现在可以正确地提供大于 2GB 的文件。

net/http/httptest

新的 Server 字段 EnableHTTP2 支持在测试服务器上启用 HTTP/2。

net/textproto

新的 MIMEHeader 方法 Values 可用于获取与规范化键关联的所有值。

net/url

当 URL 解析失败时(例如通过 ParseParseRequestURI),结果 Error 消息现在将引用无法解析的 URL。这提供了更清晰的结构并与其他解析错误保持一致。

os/signal

在 Windows 上,CTRL_CLOSE_EVENTCTRL_LOGOFF_EVENTCTRL_SHUTDOWN_EVENT 事件现在会生成 syscall.SIGTERM 信号,类似于 Control-C 和 Control-Break 生成 syscall.SIGINT 信号的方式。

插件

plugin 包现在支持 freebsd/amd64

reflect

StructOf 现在支持通过设置 StructField 元素中的 PkgPath 字段来创建具有未导出字段的结构类型。

runtime

runtime.Goexit 不能再被递归的 panic/recover 中止。

在 macOS 上,SIGPIPE 不再转发给 Go 运行时初始化之前安装的信号处理程序。这是必要的,因为 macOS 将 SIGPIPE 发送到主线程而不是写入关闭管道的线程。

runtime/pprof

生成的配置文件不再包含用于内联标记的伪 PC。内联函数的符号信息以 pprof 工具期望的格式编码。这是对最近版本中引入的回归的修复。

strconv

NumError 类型现在有一个 Unwrap 方法,可用于检索转换失败的原因。这支持使用 errors.Is 使用 NumError 值来查看底层错误是否为 strconv.ErrRangestrconv.ErrSyntax

sync

解锁高度争用的 Mutex 现在会直接将 CPU 让给下一个等待该 Mutex 的 goroutine。这显着提高了高 CPU 计数机器上高度争用的互斥锁的性能。

testing

testing 包现在支持 cleanup 函数,在测试或基准测试完成后调用,分别通过调用 T.CleanupB.Cleanup

text/template

text/template 包现在在将带括号的参数用作函数时会正确报告错误。这最常见地出现在错误情况中,例如 {{if (eq .F "a") or (eq .F "b")}}。这应该写成 {{if or (eq .F "a") (eq .F "b")}}。错误情况从未按预期工作,现在将报告错误 can't give argument to non-function

JSEscape 现在转义 &= 字符,以减轻其输出在 HTML 上下文中被误用的影响。

unicode

unicode 包和整个系统的相关支持已从 Unicode 11.0 升级到 Unicode 12.0,其中增加了 554 个新字符,包括四个新脚本和 61 个新表情符号。