Go 1.6 版本说明

Go 1.6 简介

最新的 Go 版本 1.6,在 1.5 发布六个月后发布。其大部分更改都在语言、运行时和库的实现方面。语言规范没有任何更改。与以往一样,此版本保持了 Go 1 对兼容性的承诺。我们预计几乎所有 Go 程序都将继续像以前一样编译和运行。

此版本为64 位 MIPS 上的 Linux 和 32 位 x86 上的 Android添加了新的端口;定义并强制执行了与 C 共享 Go 指针的规则;透明、自动支持 HTTP/2;以及一种新的模板重用机制。

语言更改

此版本没有语言更改。

端口

Go 1.6 为 64 位 MIPS 上的 Linux(linux/mips64linux/mips64le)添加了实验性端口。这些端口支持 cgo,但仅限于内部链接。

Go 1.6 还为 32 位 x86 上的 Android(android/386)添加了实验性端口。

在 FreeBSD 上,Go 1.6 默认使用 clang 而不是 gcc 作为外部 C 编译器。

在小端序 64 位 PowerPC 上的 Linux(linux/ppc64le)上,Go 1.6 现在支持使用外部链接的 cgo,并且功能基本齐全。

在 NaCl 上,Go 1.5 需要 SDK 版本 pepper-41。Go 1.6 添加了对更高 SDK 版本的支持。

在使用 -dynlink-shared 编译模式的 32 位 x86 系统上,寄存器 CX 现在会被某些内存引用覆盖,因此在手动编写的汇编代码中应避免使用它。有关详细信息,请参阅汇编文档

工具

Cgo

cgo 进行了重大更改,以及一项小幅更改。

重大更改是定义了与 C 代码共享 Go 指针的规则,以确保此类 C 代码可以与 Go 的垃圾回收器共存。简而言之,当将指向该内存的指针作为 cgo 调用的一部分传递给 C 时,Go 和 C 可以共享由 Go 分配的内存,前提是内存本身不包含指向 Go 分配的内存的指针,并且前提是 C 在调用返回后不会保留指针。这些规则在程序执行期间由运行时检查:如果运行时检测到违规,它会打印诊断信息并使程序崩溃。可以通过设置环境变量 GODEBUG=cgocheck=0 来禁用这些检查,但请注意,由这些检查识别的大部分代码以某种方式与垃圾回收器不兼容。禁用这些检查通常只会导致更加神秘的故障模式。修复相关代码应强烈优先于关闭检查。有关更多详细信息,请参阅cgo 文档

小幅更改是添加了显式 C.complexfloatC.complexdouble 类型,与 Go 的 complex64complex128 分开。与其他数字类型匹配,C 的复数类型和 Go 的复数类型不再可以互换。

编译器工具链

编译器工具链基本保持不变。在内部,最重大的变化是解析器现在是用手工编写的,而不是从yacc生成的。

编译器、链接器和 go 命令都有一个新的标志 -msan,类似于 -race,并且仅在 linux/amd64 上可用,它启用与Clang 内存清理器的互操作性。这种互操作性主要用于测试包含可疑 C 或 C++ 代码的程序。

链接器有一个新的选项 -libgcc,用于在链接cgo代码时设置对 C 编译器支持库的预期位置。该选项仅在使用 -linkmode=internal 时才被考虑,并且可以设置为 none 以禁用使用支持库。

在 Go 1.5 中开始的构建模式的实现已扩展到更多系统。此版本为 android/386android/amd64android/arm64linux/386linux/arm64 添加了对 c-shared 模式支持;为 linux/386linux/armlinux/amd64linux/ppc64le 添加了对 shared 模式支持;并为 android/386android/amd64android/armandroid/arm64linux/386linux/amd64linux/armlinux/arm64linux/ppc64le 添加了新的 pie 模式(生成位置无关可执行文件)支持。有关详细信息,请参阅设计文档

提醒一下,链接器的 -X 标志在 Go 1.5 中已更改。在 Go 1.4 及更早版本中,它接受两个参数,如下所示

-X importpath.name value

Go 1.5 添加了一种使用单个参数的替代语法,该参数本身是 name=value

-X importpath.name=value

在 Go 1.5 中,旧语法仍然被接受,但在打印警告,建议改为使用新语法。Go 1.6 继续接受旧语法并打印警告。Go 1.7 将删除对旧语法的支持。

Gccgo

GCC 和 Go 项目的发布计划不一致。GCC 5.0 版本包含 Go 1.4 版本的 gccgo。下一个版本,GCC 6.0,将包含 Go 1.6.1 版本的 gccgo。

Go 命令

go 命令的基本操作保持不变,但有一些值得注意的更改。

Go 1.5 引入了对供应商的实验性支持,通过将 GO15VENDOREXPERIMENT 环境变量设置为 1 来启用。Go 1.6 保留了供应商支持,不再被认为是实验性的,并默认启用它。可以通过将 GO15VENDOREXPERIMENT 环境变量设置为 0 来显式禁用它。Go 1.7 将删除对该环境变量的支持。

默认启用供应商最有可能导致的问题发生在包含名为 vendor 的现有目录的源代码树中,该目录不希望根据新的供应商语义进行解释。在这种情况下,最简单的解决办法是将目录重命名为除 vendor 之外的任何名称,并更新所有受影响的导入路径。

有关供应商的详细信息,请参阅go 命令的文档和设计文档

有一个新的构建标志 -msan,它使用对 LLVM 内存清理器支持来编译 Go。这主要用于在链接到使用内存清理器进行检查的 C 或 C++ 代码时使用。

Go doc 命令

Go 1.5 引入了go doc 命令,它允许使用仅包名的包引用,例如在 go doc http 中。在出现歧义的情况下,Go 1.5 的行为是使用词典序最早的导入路径的包。在 Go 1.6 中,通过优先考虑具有较少元素的导入路径来解决歧义,并使用词典序比较来打破平局。此更改的一个重要影响是,原始副本的包现在优先于供应商副本。成功的搜索通常也运行得更快。

Go vet 命令

go vet 命令现在诊断将函数或方法值作为参数传递给 Printf 的情况,例如在传递 f 的情况下,而本应传递 f()

性能

与以往一样,这些更改非常普遍且多样,因此难以对性能做出准确的陈述。有些程序可能运行得更快,有些可能运行得更慢。平均而言,Go 1 基准套件中的程序在 Go 1.6 中比在 Go 1.5 中运行快几个百分点。垃圾回收器的暂停时间比 Go 1.5 中的暂停时间更短,特别是对于使用大量内存的程序。

compress/bzip2compress/gzipcrypto/aescrypto/ellipticcrypto/ecdsasort 软件包的实现进行了重大优化,带来了超过 10% 的性能改进。

标准库

HTTP/2

Go 1.6 在net/http 软件包中添加了对新的HTTP/2 协议的透明支持。Go 客户端和服务器将在使用 HTTPS 时自动使用 HTTP/2(如果适用)。没有专门针对 HTTP/2 协议处理细节的导出 API,就像没有专门针对 HTTP/1.1 的导出 API 一样。

必须禁用 HTTP/2 的程序可以通过将Transport.TLSNextProto(对于客户端)或Server.TLSNextProto(对于服务器)设置为非空空映射来实现。

必须调整 HTTP/2 协议特定细节的程序可以导入并使用golang.org/x/net/http2,特别是其中的ConfigureServerConfigureTransport 函数。

运行时

运行时添加了对并行错误使用映射的轻量级、尽力而为的检测。与以往一样,如果一个 goroutine 正在写入映射,则任何其他 goroutine 都不能同时读取或写入该映射。如果运行时检测到这种情况,它会打印诊断信息并使程序崩溃。了解问题的最佳方法是在竞争检测器下运行程序,它将更可靠地识别竞争并提供更多详细信息。

对于导致程序结束的 panic,运行时现在默认仅打印正在运行的 goroutine 的堆栈,而不是所有现有 goroutine 的堆栈。通常,只有当前 goroutine 与 panic 相关,因此省略其他 goroutine 会显着减少崩溃消息中无关输出的数量。要在崩溃消息中查看所有 goroutine 的堆栈,请将环境变量 GOTRACEBACK 设置为 all 或在崩溃前调用debug.SetTraceback,然后重新运行程序。有关详细信息,请参阅运行时文档

更新:旨在转储整个程序状态的未捕获恐慌,例如在检测到超时或显式处理接收到的信号时,现在应该在恐慌之前调用debug.SetTraceback("all")。搜索使用 signal.Notify 可能有助于识别此类代码。

在 Windows 上,Go 1.5 及更早版本的 Go 程序通过调用timeBeginPeriod(1)在启动时强制将全局 Windows 计时器分辨率设置为 1ms。Go 不再需要此功能来获得良好的调度程序性能,并且更改全局计时器分辨率会导致某些系统出现问题,因此已删除该调用。

当使用-buildmode=c-archive-buildmode=c-shared构建存档或共享库时,信号的处理方式已更改。在 Go 1.5 中,存档或共享库将为大多数信号安装信号处理程序。在 Go 1.6 中,它将只为处理 Go 代码中运行时恐慌所需的同步信号安装信号处理程序:SIGBUS、SIGFPE、SIGSEGV。有关更多详细信息,请参阅 os/signal 包。

反射

reflect 包已 解决 gc 和 gccgo 工具链之间长期存在的关于包含导出字段的嵌入式未导出结构类型的不兼容性。使用反射遍历数据结构的代码,尤其是为了实现类似于 encoding/jsonencoding/xml 包的序列化,可能需要更新。

当使用反射遍历嵌入式未导出结构类型字段进入该结构的导出字段时,就会出现此问题。在这种情况下,reflect 错误地报告了嵌入式字段为导出字段,通过返回一个空的Field.PkgPath。现在它正确地报告了该字段为未导出字段,但在评估对结构内包含的导出字段的访问时会忽略这一事实。

更新:通常,以前遍历结构并使用

f.PkgPath != ""

来排除不可访问字段的代码现在应该使用

f.PkgPath != "" && !f.Anonymous

例如,请参阅对 encoding/jsonencoding/xml 实现的更改。

排序

sort 包中,Sort 的实现已被重写,以减少约 10% 对 InterfaceLessSwap方法的调用次数,并相应地节省了总体时间。新算法确实会为比较相等的值选择不同的排序顺序(对于Less(i, j)Less(j, i) 为假的那些对)。

更新Sort 的定义不保证相等值的最终顺序,但新的行为仍然可能破坏期望特定顺序的程序。此类程序应该要么细化其Less实现以报告所需的顺序,要么切换到 Stable,它保留相等值的原始输入顺序。

模板

text/template 包中,有两个重要的新功能可以使编写模板更容易。

首先,现在可以 修剪模板操作周围的空格,这可以使模板定义更具可读性。操作开头的一个减号表示修剪操作之前的空格,操作结尾的一个减号表示修剪操作之后的空格。例如,模板

{{23 -}}
   <
{{- 45}}

格式化为23<45

其次,新的 {{block}} 操作,加上允许重新定义命名模板,提供了一种简单的方法来定义可以替换为不同实例化的模板片段。在text/template 包中,有一个 示例 演示了此新功能。

对库的次要更改