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 上 32 位二进制文件(darwin/arm 端口)的 Go 版本。Go 继续支持 64 位 darwin/arm64 端口。

Windows

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

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

WebAssembly

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

js.Value 值不能再使用 == 运算符进行比较,而必须使用其 Equal 方法进行比较。

js.Value 现在具有 IsUndefinedIsNullIsNaN 方法。

RISC-V

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

FreeBSD

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

Native Client (NaCl)

如 Go 1.13 发布说明中所述,Go 1.14 停止支持 Native Client 平台(GOOS=nacl)。

Illumos

运行时现在会尊重区域 CPU 上限(zone.cpu-cap 资源控制)以用于 runtime.NumCPUGOMAXPROCS 的默认值。

工具

Go 命令

供应商

当主模块包含顶级 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 downloadgo 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,而无需担心开销问题。

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

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

页面分配器效率更高,并且在 GOMAXPROCS 的高值下产生的锁争用明显减少。这在并行且高速率执行的大量分配的更低延迟和更高吞吐量方面最为明显。

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

编译器

此版本添加了-d=checkptr作为编译时选项,用于添加检测代码是否遵循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标志输出关键优化的机器可读日志,包括内联、逃逸分析、边界检查消除和空检查消除。

详细的逃逸分析诊断(-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.CertificatesConfig.GetCertificate现在如果设置了Config.GetConfigForClient,则都可以为 nil。如果回调既不返回证书也不返回错误,则现在发送unrecognized_name

新的CertificateRequestInfo.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 Data添加任意新的 DWARF 部分。

新方法(*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

plugin包现在支持freebsd/amd64

reflect

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

runtime

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

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

runtime/pprof

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

strconv

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

sync

解锁竞争激烈的 Mutex 现在会直接将 CPU 让给等待该 Mutex 的下一个 goroutine。这显著提高了在 CPU 核心数量多的机器上竞争激烈的互斥锁的性能。

testing

testing 包现在支持清理函数,在测试或基准测试完成后调用,分别通过调用 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 个新字符,包括 4 种新的文字系统和 61 个新的表情符号。