Go 1.11 发布说明

Go 1.11 简介

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

语言更改

语言规范没有任何更改。

端口

Go 1.10 发布说明中所述,Go 1.11 现在需要 OpenBSD 6.2 或更高版本、macOS 10.10 Yosemite 或更高版本或 Windows 7 或更高版本;对这些操作系统的先前版本的支持已删除。

Go 1.11 支持即将发布的 OpenBSD 6.4 版本。由于 OpenBSD 内核中的更改,旧版本的 Go 将无法在 OpenBSD 6.4 上运行。

在 i386 硬件上的 NetBSD 上存在 已知问题

竞态检测器现在在 linux/ppc64le 上受支持,并且在 netbsd/amd64 上也得到了一定程度的支持。NetBSD 竞态检测器支持存在 已知问题

内存清理程序 (-msan) 现在在 linux/arm64 上受支持。

构建模式 c-sharedc-archive 现在在 freebsd/amd64 上受支持。

在 64 位 MIPS 系统上,新的环境变量设置 GOMIPS64=hardfloat(默认值)和 GOMIPS64=softfloat 选择是使用硬件指令还是软件模拟进行浮点计算。对于 32 位系统,环境变量仍然是 GOMIPS,如 Go 1.10 中添加的那样

在软浮点 ARM 系统 (GOARM=5) 上,Go 现在使用更有效的软件浮点接口。这对 Go 代码是透明的,但未在 GOARM 上受保护的使用的浮点指令的 ARM 汇编将中断,并且必须移植到 新的接口

ARMv7 上的 Go 1.11 不再需要使用 KUSER_HELPERS 配置的 Linux 内核。此设置在默认内核配置中启用,但在精简配置中有时会禁用。

WebAssembly

Go 1.11 添加了一个到 WebAssembly (js/wasm) 的实验性端口。

Go 程序目前编译为一个 WebAssembly 模块,其中包含用于 goroutine 调度、垃圾回收、映射等功能的 Go 运行时。因此,结果大小至少约为 2 MB,或压缩后为 500 KB。Go 程序可以使用新的实验性 syscall/js 包调用 JavaScript。二进制文件大小和与其他语言的互操作性尚未成为优先事项,但可能会在将来的版本中得到解决。

由于添加了新的 GOOS 值“js”和 GOARCH 值“wasm”,因此现在将忽略名为 *_js.go*_wasm.go 的 Go 文件 Go 工具,除非正在使用这些 GOOS/GOARCH 值。如果您有与这些模式匹配的现有文件名,则需要重命名它们。

有关更多信息,请参阅 WebAssembly wiki 页面

RISC-V GOARCH 值已保留

主 Go 编译器尚不支持 RISC-V 架构但我们已保留了 GOARCH 值“riscv”和“riscv64”,如 Gccgo 所用,它确实支持 RISC-V。这意味着现在还将忽略名为 *_riscv.go 的 Go 文件 Go 工具,除非正在使用这些 GOOS/GOARCH 值。

工具

模块、包版本控制和依赖项管理

Go 1.11 添加了对 “模块”这一新概念 的初步支持,它是 GOPATH 的替代方案,并集成了对版本控制和包分发的支持。使用模块,开发人员不再局限于在 GOPATH 内工作,版本依赖项信息是显式但轻量级的,并且构建更加可靠且可重现。

模块支持被认为是实验性的。详细信息可能会根据 Go 1.11 用户的反馈而更改,并且我们还计划推出更多工具。尽管模块支持的详细信息可能会更改,但使用 Go 1.11 转换为模块的项目将继续与 Go 1.12 及更高版本一起使用。如果您在使用模块时遇到错误,请 提交问题,以便我们能够修复它们。有关更多信息,请参阅 go 命令文档

导入路径限制

因为 Go 模块支持在命令行操作中为 @ 符号赋予特殊含义,所以 go 命令现在不允许使用包含 @ 符号的导入路径。go get 从未允许使用此类导入路径,因此此限制只能影响通过其他方式构建自定义 GOPATH 树的用户。

包加载

新包 golang.org/x/tools/go/packages 提供了一个简单的 API,用于定位和加载 Go 源代码的包。虽然尚未成为标准库的一部分,但对于许多任务而言,它有效地取代了 go/build 包,该包的 API 无法完全支持模块。因为它运行外部查询命令(例如 go list)以获取有关 Go 包的信息,因此它能够构建同样适用于替代构建系统(如 BazelBuck)的分析工具。

构建缓存要求

Go 1.11 将是最后一个支持设置环境变量 GOCACHE=off 以禁用 构建缓存(在 Go 1.10 中引入)的版本。从 Go 1.12 开始,构建缓存将是必需的,作为消除 $GOPATH/pkg 的一步。上面描述的模块和包加载支持已经要求启用构建缓存。如果您已禁用构建缓存以避免遇到的问题,请 提交问题 以告知我们。

编译器工具链

现在默认情况下,更多函数有资格进行内联,包括调用 panic 的函数。

编译器工具链现在支持 行指令 中的列信息。

已引入新的包导出数据格式。这对于最终用户来说应该是透明的,除了加快大型 Go 项目的构建时间之外。如果它确实导致问题,可以通过在构建二进制文件时将 -gcflags=all=-iexport=false 传递给 go 工具来再次将其关闭。

编译器现在拒绝在类型切换保护中声明的未使用的变量,例如以下示例中的 x

func f(v interface{}) {
    switch x := v.(type) {
    }
}

这已被 gccgogo/types 拒绝。

汇编器

amd64 的汇编器现在接受 AVX512 指令。

调试

编译器现在为优化的二进制文件生成更准确的调试信息,包括变量位置信息、行号和断点位置。这应该可以使调试无需 -N -l 编译的二进制文件成为可能。调试信息的质量仍然存在一些限制,其中一些是根本性的,另一些将在将来的版本中继续改进。

DWARF 部分现在默认情况下会被压缩,因为编译器产生了扩展的和更准确的调试信息。这对大多数 ELF 工具(例如 Linux 和 *BSD 上的调试器)是透明的,并且所有平台上的 Delve 调试器都支持它,但在 macOS 和 Windows 上的原生工具中支持有限。要禁用 DWARF 压缩,请在构建二进制文件时将 -ldflags=-compressdwarf=false 传递给 go 工具。

Go 1.11 添加了对从调试器内部调用 Go 函数的实验性支持。例如,这对于在断点处暂停时调用 String 方法很有用。目前仅 Delve(版本 1.1.0 及更高版本)支持此功能。

测试

从 Go 1.10 开始,go test 命令会在测试的包上运行 go vet,以在运行测试之前识别问题。由于 vet 会在运行之前使用 go/types 对代码进行类型检查,因此现在不会进行类型检查的测试将失败。特别是,包含在使用 Go 1.10 编译的闭包中未使用的变量的测试,因为 Go 编译器错误地接受了它们 (问题 #3059),但现在将失败,因为 go/types 在这种情况下会正确报告“未使用的变量”错误。

go test-memprofile 标志现在默认为“allocs”配置文件,该配置文件记录自测试开始以来分配的总字节数(包括垃圾回收的字节)。

Vet

当要分析的包未进行类型检查时,go vet 命令现在会报告致命错误。以前,类型检查错误只会导致打印警告,并且 vet 会以状态 1 退出。

此外,go vet 在格式检查 printf 包装器时变得更加健壮。Vet 现在可以检测到此示例中的错误

func wrapper(s string, args ...interface{}) {
    fmt.Printf(s, args...)
}

func main() {
    wrapper("%s", 42)
}

跟踪

借助新的runtime/trace包的用户注释 API,用户可以在执行跟踪中记录应用程序级信息,并创建相关 goroutine 组。go tool trace命令会在跟踪视图和新的用户任务/区域分析页面中可视化这些信息。

Cgo

从 Go 1.10 开始,cgo 将某些 C 指针类型转换为 Go 类型uintptr。这些类型包括 Darwin 的 CoreFoundation 框架中的CFTypeRef层次结构以及 Java 的 JNI 接口中的jobject层次结构。在 Go 1.11 中,对检测这些类型的代码进行了一些改进。使用这些类型的代码可能需要进行一些更新。有关详细信息,请参阅Go 1.10 发行说明

Go 命令

现在可以使用环境变量GOFLAGSgo命令设置默认标志。这在某些情况下很有用。由于 DWARF,链接在性能较低的系统上可能会明显变慢,用户可能希望默认设置-ldflags=-w。对于模块,某些用户和 CI 系统始终希望使用供应商,因此他们应该默认设置-mod=vendor。有关更多信息,请参阅go命令文档

Godoc

Go 1.11 将是最后一个支持godoc命令行接口的版本。在未来的版本中,godoc将只作为一个 Web 服务器。用户应该使用go doc来获取命令行帮助输出。

godoc Web 服务器现在显示了哪个版本的 Go 引入了新的 API 功能。类型、函数和方法的初始 Go 版本右对齐显示。例如,请参阅UserCacheDir,右侧显示“1.11”。对于结构体字段,当结构体字段是在与类型本身引入不同的 Go 版本中添加时,会添加内联注释。有关结构体字段示例,请参阅ClientTrace.Got1xxResponse

Gofmt

Go 源代码默认格式化的一个小细节发生了变化。在格式化带有内联注释的表达式列表时,注释是根据启发式算法对齐的。但是,在某些情况下,对齐可能会过于容易地被拆分,或者引入过多的空白。启发式算法已更改为对人工编写的代码表现得更好。

请注意,这些类型的对 gofmt 的微小更新预计会不时发生。通常,需要一致格式化 Go 源代码的系统应该使用特定版本的gofmt二进制文件。有关更多信息,请参阅go/format包文档。

运行

go run命令现在允许使用单个导入路径、目录名称或与单个包匹配的模式。这允许使用go run pkggo run dir,最重要的是go run .

运行时

运行时现在使用稀疏堆布局,因此 Go 堆的大小不再受限(以前,限制为 512GiB)。这还修复了混合 Go/C 二进制文件或使用-race编译的二进制文件中罕见的“地址空间冲突”错误。

在 macOS 和 iOS 上,运行时现在使用libSystem.dylib而不是直接调用内核。这应该使 Go 二进制文件与未来版本的 macOS 和 iOS 更加兼容。syscall包仍然进行直接系统调用;计划在将来的版本中修复此问题。

性能

与往常一样,更改非常普遍和多样,因此难以对性能做出精确的陈述。由于更好的代码生成和核心库中的优化,大多数程序的运行速度应该会略有提升。

math/big包进行了多项性能更改,并且在整个树中进行了许多特定于GOARCH=arm64的更改。

编译器工具链

编译器现在优化以下形式的映射清除操作:

for k := range m {
    delete(m, k)
}

编译器现在优化以下形式的切片扩展append(s, make([]T, n)...)

编译器现在执行更积极的边界检查和分支消除。值得注意的是,它现在识别传递关系,因此如果i<j并且j<len(s),它可以使用这些事实来消除s[i]的边界检查。它还理解简单的算术运算,例如s[i-10],并且可以识别循环中更多归纳情况。此外,编译器现在使用边界信息来更积极地优化移位操作。

标准库

标准库的所有更改都是次要的。

库的次要更改

与往常一样,对库进行了各种次要更改和更新,并牢记 Go 1兼容性承诺

加密

某些加密操作,包括ecdsa.Signrsa.EncryptPKCS1v15rsa.GenerateKey,现在会随机读取额外的随机字节以确保测试不依赖于内部行为。

crypto/cipher

新函数NewGCMWithTagSize实现了具有非标准标签长度的伽罗瓦计数器模式,以与现有密码系统兼容。

crypto/rsa

PublicKey现在实现了一个Size方法,该方法以字节为单位返回模数大小。

crypto/tls

ConnectionState的新ExportKeyingMaterial方法允许根据 RFC 5705导出绑定到连接的密钥材料。

crypto/x509

当不存在主题备用名称时,将CommonName字段视为主机名的已弃用旧行为现在在 CN 不是有效主机名时被禁用。可以通过将实验值x509ignoreCN=1添加到GODEBUG环境变量来完全忽略CommonName。当忽略 CN 时,没有 SAN 的证书将在具有名称约束的链下验证,而不是返回NameConstraintsWithoutSANs

扩展密钥使用限制仅在它们出现在VerifyOptionsKeyUsages字段中时才被检查,而不是始终被检查。这与 Go 1.9 及更早版本的行为相匹配。

SystemCertPool返回的值现在被缓存,并且可能无法反映调用之间系统更改。

debug/elf

添加了更多ELFOSABIEM常量。

encoding/asn1

MarshalUnmarshal现在支持字段的“私有”类注释。

encoding/base32

解码器现在一致地为不完整的块返回io.ErrUnexpectedEOF。以前它会在某些情况下返回io.EOF

encoding/csv

Reader现在拒绝尝试将Comma字段设置为双引号字符,因为双引号字符在 CSV 中已经具有特殊含义。

html/template

当将类型化接口值传递给隐式转义器函数时,该包已更改其行为。以前,这样的值会被写出为<nil>的(转义形式)。现在,这些值将被忽略,就像未类型化的nil值一样(并且始终被忽略)。

image/gif

现在支持非循环动画 GIF。它们以LoopCount为 -1 表示。

io/ioutil

TempFile函数现在支持指定文件名中随机字符的位置。如果prefix参数包含“*”,则随机字符串将替换“*”。例如,prefix参数为“myname.*.bat”将导致随机文件名,例如“myname.123456.bat”。如果没有包含“*”,则保留旧行为,并将随机数字追加到末尾。

math/big

ModInverse现在在 g 和 n 不互质时返回 nil。以前的结果未定义。

mime/multipart

对缺少/为空的文件名的表单数据的处理已恢复到 Go 1.9 中的行为:在表单数据的Form中,该值在Value字段中可用,而不是File字段。在 Go 版本 1.10 到 1.10.3 中,具有缺少/为空的文件名和非空“Content-Type”字段的表单数据部分存储在File字段中。此更改是 1.10 中的一个错误,已恢复到 1.9 的行为。

mime/quotedprintable

为了支持在野外发现的无效输入,该包现在允许非 ASCII 字节,但不会验证其编码。

网络

新的ListenConfig类型和新的Dialer.Control字段分别允许在接受和创建连接之前设置套接字选项。

syscall.RawConnReadWrite方法现在在 Windows 上可以正常工作。

net包现在在 Linux 上使用splice系统调用(在TCPConn.ReadFrom中,由io.Copy调用)在 TCP 连接之间复制数据时。结果是更快的、更高效的 TCP 代理。

TCPConn.FileUDPConn.FileUnixConn.FileIPConn.File方法不再将返回的*os.File置于阻塞模式。

net/http

Transport类型具有一个新的MaxConnsPerHost选项,允许限制每个主机的最大连接数。

Cookie 类型新增了一个 SameSite 字段(也是一个新类型,命名为 SameSite),用于表示最近大多数浏览器支持的新 cookie 属性。net/httpTransport 本身不使用 SameSite 属性,但该包支持解析和序列化该属性以供浏览器使用。

在调用 ShutdownClose 之后,不再允许重用 Server。这在过去从未正式支持过,并且经常会出现意外的行为。现在,在关闭或停止服务后,对服务器的 Serve 方法的所有后续调用都将返回错误。

现在为 HTTP 状态码 421 定义了常量 StatusMisdirectedRequest

HTTP 服务器在收到流水线式 HTTP/1.1 请求时,将不再取消上下文或在 CloseNotifier 通道上发送数据。浏览器不使用 HTTP 流水线,但某些客户端(例如 Debian 的 apt)可能会配置为使用它。

ProxyFromEnvironment(由 DefaultTransport 使用)现在支持 NO_PROXY 环境变量中的 CIDR 表示法和端口。

net/http/httputil

ReverseProxy 有一个新的 ErrorHandler 选项,允许更改错误处理方式。

ReverseProxy 现在还将“TE: trailers”请求头传递给后端,这是 gRPC 协议的要求。

os

新的 UserCacheDir 函数返回用于用户特定缓存数据的默认根目录。

新的 ModeIrregular 是一个 FileMode 位,表示文件不是常规文件,但对其一无所知,或者它不是套接字、设备、命名管道、符号链接或 Go 为其定义了模式位的其他文件类型。

Symlink 现在可以在启用了开发者模式的 Windows 10 上为非特权用户工作。

当将非阻塞描述符传递给 NewFile 时,生成的 *File 将保持非阻塞模式。这意味着该 *File 的 I/O 将使用运行时轮询器而不是单独的线程,并且 SetDeadline 方法将起作用。

os/signal

新的 Ignored 函数报告当前是否忽略了信号。

os/user

os/user 包现在可以使用构建标签“osusergo”以纯 Go 模式构建,独立于环境变量 CGO_ENABLED=0 的使用。以前,使用该包的纯 Go 实现的唯一方法是禁用整个程序的 cgo 支持。

runtime

设置 GODEBUG=tracebackancestors=N 环境变量现在会将跟踪回溯扩展到创建 goroutine 的堆栈,其中 N 限制了要报告的祖先 goroutine 的数量。

runtime/pprof

此版本添加了一种新的“allocs”配置文件类型,该类型分析程序开始以来分配的总字节数(包括垃圾回收的字节)。这与在 -alloc_space 模式下查看的现有“heap”配置文件相同。现在 go test -memprofile=... 报告“allocs”配置文件而不是“heap”配置文件。

sync

互斥锁配置文件现在包括 RWMutex 的读写器争用。写写器争用已包含在互斥锁配置文件中。

syscall

在 Windows 上,一些字段已从 uintptr 更改为新的 Pointer 类型,以避免 Go 的垃圾回收器出现问题。对 golang.org/x/sys/windows 包也进行了相同的更改。对于受影响的任何代码,用户应首先从 syscall 包迁移到 golang.org/x/sys/windows 包,然后更改为使用 Pointer,同时遵守 unsafe.Pointer 转换规则

在 Linux 上,Faccessatflags 参数现在与 glibc 中的实现相同。在早期的 Go 版本中,忽略了 flags 参数。

在 Linux 上,Fchmodatflags 参数现在已通过验证。Linux 的 fchmodat 不支持 flags 参数,因此我们现在模仿 glibc 的行为,如果它不为零,则返回错误。

text/scanner

Scanner.Scan 方法现在返回 RawString 令牌而不是 String 以获取原始字符串文字。

text/template

现在可以通过 = 令牌通过赋值修改模板变量。

  {{ $v := "init" }}
  {{ if true }}
    {{ $v = "changed" }}
  {{ end }}
  v: {{ $v }} {{/* "changed" */}}

在以前的版本中,传递给模板函数的未类型化 nil 值会被忽略。现在它们作为普通参数传递。

time

现在支持解析由符号和偏移量表示的时区。在以前的版本中,数字时区名称(例如 +03)不被视为有效,并且仅在期望时区名称时接受三个字母的缩写(例如 MST)。