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/mips64
和 linux/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 版本的支持。
在 32 位 x86 系统上,使用 -dynlink
或 -shared
编译模式时,寄存器 CX 现在会被某些内存引用覆盖,应避免在手写的汇编代码中使用。有关详细信息,请参阅 汇编文档。
工具
Cgo
cgo
有一个主要更改,以及一个次要更改。
主要更改是定义了与 C 代码共享 Go 指针的规则,以确保此类 C 代码可以与 Go 的垃圾回收器共存。简而言之,Go 和 C 可以在作为 cgo
调用的一部分将指向 Go 分配内存的指针传递给 C 时共享 Go 分配的内存,前提是内存本身不包含指向 Go 分配内存的指针,并且 C 在调用返回后不保留该指针。这些规则在程序执行期间由运行时检查:如果运行时检测到违规,它会打印诊断信息并使程序崩溃。这些检查可以通过设置环境变量 GODEBUG=cgocheck=0
来禁用,但请注意,绝大多数被检查识别出的代码都以这样或那样的方式与垃圾回收微妙地不兼容。禁用检查通常只会导致更神秘的故障模式。强烈建议修复相关代码,而不是关闭检查。有关详细信息,请参阅 cgo
文档。
次要更改是新增了显式 C.complexfloat
和 C.complexdouble
类型,与 Go 的 complex64
和 complex128
不同。与其他数值类型一样,C 的复数类型和 Go 的复数类型不再可以互换。
编译器工具链
编译器工具链基本保持不变。在内部,最重要的变化是解析器现在是手写的,而不是从 yacc 生成的。
编译器、链接器和 go
命令新增了一个 -msan
标志,类似于 -race
,并且只在 linux/amd64 上可用,它支持与 Clang MemorySanitizer 的交互。这种交互主要用于测试包含可疑 C 或 C++ 代码的程序。
链接器新增了一个 -libgcc
选项,用于在链接 cgo
代码时设置 C 编译器支持库的预期位置。该选项仅在使用 -linkmode=internal
时才会被考虑,并且可以设置为 none
以禁用支持库的使用。
Go 1.5 中开始的构建模式实现 已扩展到更多系统。此版本新增了对 android/386
、android/amd64
、android/arm64
、linux/386
和 linux/arm64
上的 c-shared
模式的支持;对 linux/386
、linux/arm
、linux/amd64
和 linux/ppc64le
上的 shared
模式的支持;以及对 android/386
、android/amd64
、android/arm
、android/arm64
、linux/386
、linux/amd64
、linux/arm
、linux/arm64
和 linux/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 版本包含 Go 1.4 版本的 gccgo。下一个版本 GCC 6 将包含 Go 1.6.1 版本的 gccgo。
Go 命令
go
命令的基本操作没有改变,但有许多值得注意的更改。
Go 1.5 引入了实验性的 vendoring 支持,通过将 GO15VENDOREXPERIMENT
环境变量设置为 1
启用。Go 1.6 保留了 vendoring 支持,不再认为是实验性的,并默认启用。可以通过将 GO15VENDOREXPERIMENT
环境变量设置为 0
来显式禁用。Go 1.7 将取消对该环境变量的支持。
默认启用 vendoring 最可能导致的问题发生在包含现有名为 vendor
目录的源代码树中,该目录不希望根据新的 vendoring 语义进行解释。在这种情况下,最简单的修复方法是将目录重命名为 vendor
以外的任何名称,并更新任何受影响的导入路径。
有关 vendoring 的详细信息,请参阅 go
命令 和 设计文档 的文档。
新增了一个构建标志 -msan
,它编译 Go 以支持 LLVM 内存清理器。这主要用于链接到正在使用内存清理器检查的 C 或 C++ 代码时。
Go doc 命令
Go 1.5 引入了 go doc
命令,它允许仅使用包名引用包,例如 go
doc
http
。在 Go 1.5 中,如果存在歧义,则使用词典顺序最早的导入路径的包。在 Go 1.6 中,通过优先选择元素较少的导入路径来解决歧义,并使用词典比较来打破平局。这一变化的一个重要影响是现在优先选择包的原始副本而不是 vendored 副本。成功的搜索也往往运行得更快。
Go vet 命令
go vet
命令现在会诊断将函数或方法值作为参数传递给 Printf
的情况,例如在预期 f()
的地方传递 f
。
性能
一如既往,这些变化非常普遍和多样,因此很难对性能做出精确的说明。有些程序可能会运行得更快,有些则会更慢。平均而言,Go 1 基准测试套件中的程序在 Go 1.6 中比在 Go 1.5 中运行速度快百分之几。垃圾回收器的暂停时间甚至比 Go 1.5 更短,特别是对于使用大量内存的程序。
在 compress/bzip2
、compress/gzip
、crypto/aes
、crypto/elliptic
、crypto/ecdsa
和 sort
包的实现方面,已进行了重大优化,带来了超过 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
,特别是其 ConfigureServer 和 ConfigureTransport 函数。
运行时
运行时已添加了对并发滥用映射的轻量级、尽力检测。一如既往,如果一个 goroutine 正在写入映射,则其他 goroutine 不应并发读取或写入映射。如果运行时检测到此情况,它将打印诊断信息并使程序崩溃。要了解更多关于此问题的信息,最好的方法是在 竞争检测器 下运行程序,它将更可靠地识别竞争并提供更多详细信息。
对于导致程序终止的 panic,运行时现在默认只打印正在运行的 goroutine 的堆栈,而不是所有现有 goroutine。通常只有当前 goroutine 与 panic 相关,因此省略其他 goroutine 显著减少了崩溃消息中无关的输出。要在崩溃消息中查看所有 goroutine 的堆栈,请将环境变量 GOTRACEBACK
设置为 all
或在崩溃前调用 debug.SetTraceback
,然后重新运行程序。有关详细信息,请参阅 运行时文档。
更新:旨在转储整个程序状态的未捕获 panic(例如检测到超时或显式处理接收到的信号时)现在应在 panic 之前调用 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 代码中的运行时 panic 所需的同步信号安装信号处理程序:SIGBUS、SIGFPE、SIGSEGV。有关详细信息,请参阅 os/signal 包。
反射
reflect
包已 解决了 gc 和 gccgo 工具链之间关于包含导出字段的嵌入式未导出结构类型长期存在的不兼容性。使用反射遍历数据结构的代码,特别是实现 encoding/json
和 encoding/xml
包风格的序列化的代码,可能需要更新。
当使用反射遍历嵌入式未导出结构类型字段到该结构的导出字段时,会出现问题。在这种情况下,reflect
曾错误地将嵌入式字段报告为已导出,通过返回空 Field.PkgPath
。现在它正确地将字段报告为未导出,但在评估对结构中包含的导出字段的访问时忽略了该事实。
更新:通常,以前遍历结构并使用
f.PkgPath != ""
排除不可访问字段的代码现在应该使用
f.PkgPath != "" && !f.Anonymous
例如,请参阅 encoding/json
和 encoding/xml
实现的更改。
排序
在 sort
包中,Sort
的实现已重写,使对 Interface
的 Less
和 Swap
方法的调用减少了大约 10%,从而节省了总体时间。新算法对于比较相等的值(即 Less(i,
j)
和 Less(j,
i)
都为 false 的那些对)确实选择了与以前不同的排序。
更新:Sort
的定义不保证相等值的最终顺序,但新行为仍可能破坏预期特定顺序的程序。此类程序应完善其 Less
实现以报告所需顺序,或切换到 Stable
,后者保留相等值的原始输入顺序。
模板
在 text/template 包中,有两个重要的新功能可以使编写模板更容易。
首先,现在可以 修剪模板操作周围的空格,这可以使模板定义更具可读性。操作开头的减号表示修剪操作之前的空格,操作结尾的减号表示修剪操作之后的空格。例如,模板
{{23 -}}
<
{{- 45}}
格式化为 23<45
。
其次,新的 {{block}}
操作,结合允许重新定义命名模板,提供了一种定义模板片段的简单方法,这些片段可以在不同的实例化中替换。在 text/template
包中有一个 示例 演示了这一新功能。
对库的微小更改
archive/tar
包的实现纠正了文件格式在罕见边缘情况下的许多错误。一个可见的变化是,Reader
类型的Read
方法现在将特殊文件类型的内容显示为空,立即返回io.EOF
。- 在
archive/zip
包中,Reader
类型现在有一个RegisterDecompressor
方法,而Writer
类型现在有一个RegisterCompressor
方法,从而可以控制单个 zip 文件的压缩选项。这些方法优先于已有的全局RegisterDecompressor
和RegisterCompressor
函数。 bufio
包的Scanner
类型现在有一个Buffer
方法,用于指定在扫描过程中使用的初始缓冲区和最大缓冲区大小。这使得在需要时可以扫描大于MaxScanTokenSize
的标记。同样对于Scanner
,该包现在定义了ErrFinalToken
错误值,供 拆分函数 使用以中止处理或返回最终的空标记。compress/flate
包已弃用其ReadError
和compress/flate
、compress/gzip
和compress/zlib
包现在对截断的输入流报告io.ErrUnexpectedEOF
,而不是io.EOF
。- 在 GCM 解密失败的情况下,
crypto/cipher
包现在会覆盖目标缓冲区。这是为了让 AESNI 代码避免使用临时缓冲区。 crypto/tls
包有一些小的改动。现在它允许当Config
的Certificates
为 nil 时Listen
成功,只要设置了GetCertificate
回调;它增加了对 RSA 与 AES-GCM 密码套件的支持;它还增加了一个RecordHeaderError
,允许客户端(特别是net/http
包)在尝试与非 TLS 服务器建立 TLS 连接时报告更好的错误。crypto/x509
包现在允许证书包含负序列号(技术上是错误,但实际上很常见),并且它定义了一个新的InsecureAlgorithmError
,以便在拒绝使用 MD5 等不安全算法签名的证书时提供更好的错误消息。debug/dwarf
和debug/elf
包共同增加了对压缩 DWARF 段的支持。用户代码无需更新:读取时会自动解压缩这些段。debug/elf
包增加了对一般压缩 ELF 段的支持。用户代码无需更新:读取时会自动解压缩这些段。但是,压缩的Sections
不支持随机访问:它们具有 nilReaderAt
字段。encoding/asn1
包现在导出了 标签和类常量,这些常量对于高级解析 ASN.1 结构很有用。- 同样在
encoding/asn1
包中,Unmarshal
现在拒绝各种非标准的整数和长度编码。 encoding/base64
包的Decoder
已修复,可以处理输入的最后字节。以前它尽可能多地处理四字节标记,但忽略了剩余的部分,最多三个字节。因此,Decoder
现在正确处理未填充编码(如 RawURLEncoding)中的输入,但它也拒绝填充编码中截断或以无效字节(如尾随空格)结尾的输入。encoding/json
包现在在 marshalingNumber
之前检查其语法,要求它符合 JSON 规范中的数值。与以前的版本一样,零Number
(空字符串)被 marshaling 为字面量 0(零)。encoding/xml
包的Marshal
函数现在支持cdata
属性,例如chardata
,但将其参数编码在一个或多个<![CDATA[ ... ]]>
标签中。- 同样在
encoding/xml
包中,Decoder
的Token
方法在遇到所有开放标签未关闭的 EOF 时现在会报告错误,这与其输入中标签必须正确匹配的一般要求一致。要避免该要求,请使用RawToken
。 fmt
包现在允许任何整数类型作为Printf
的*
宽度和精度规范的参数。在以前的版本中,*
的参数必须是int
类型。- 同样在
fmt
包中,Scanf
现在可以使用 %X 扫描十六进制字符串,作为 %x 的别名。两种格式都接受任何大小写混合的十六进制。 image
和image/color
包添加了NYCbCrA
和NYCbCrA
类型,以支持具有非预乘 Alpha 的 Y’CbCr 图像。io
包的MultiWriter
实现现在实现了WriteString
方法,供WriteString
使用。- 在
math/big
包中,Int
添加了Append
和Text
方法,以提供更多打印控制。 - 同样在
math/big
包中,Float
现在实现了encoding.TextMarshaler
和encoding.TextUnmarshaler
,允许它以自然形式通过encoding/json
和encoding/xml
包进行序列化。 - 同样在
math/big
包中,Float
的Append
方法现在支持特殊的精度参数 -1。正如在strconv.ParseFloat
中一样,精度 -1 表示使用最少的位数,以便Parse
将结果读入相同精度的Float
时将产生原始值。 math/rand
包新增了Read
函数,同样Rand
也新增了Read
方法。这些使得生成伪随机测试数据更加容易。请注意,与该包的其余部分一样,这些不应在加密环境中使用;为此目的,请改用crypto/rand
包。net
包的ParseMAC
函数现在接受 20 字节的 IP-over-InfiniBand (IPoIB) 链路层地址。- 同样在
net
包中,DNS 查找有一些变化。首先,DNSError
错误实现现在实现了Error
,特别是其新的IsTemporary
方法对于 DNS 服务器错误返回 true。其次,DNS 查找函数(例如LookupAddr
)现在在 Plan 9 和 Windows 上返回带根域名(带尾随点)的域名,以匹配 Go 在 Unix 系统上的行为。 net/http
包除了已经讨论过的 HTTP/2 支持之外,还有一些小的补充。首先,FileServer
现在按文件名对其生成的目录列表进行排序。其次,如果请求的 URL 路径包含“..” (点点) 作为路径元素,ServeFile
函数现在拒绝提供结果。程序通常应该使用FileServer
和Dir
,而不是直接调用ServeFile
。需要响应包含点点 URL 的请求提供文件内容的程序仍然可以调用ServeContent
。第三,Client
现在允许用户代码设置Expect:
100-continue
头(参见Transport.ExpectContinueTimeout
)。第四,有 五个新的错误代码:StatusPreconditionRequired
(428)、StatusTooManyRequests
(429)、StatusRequestHeaderFieldsTooLarge
(431) 和StatusNetworkAuthenticationRequired
(511) 来自 RFC 6585,以及最近批准的StatusUnavailableForLegalReasons
(451)。第五,CloseNotifier
的实现和文档已大幅更改。Hijacker
接口现在在以前使用CloseNotifier
的连接上也能正常工作。文档现在描述了CloseNotifier
何时应该工作。- 同样在
net/http
包中,关于处理其Method
字段设置为空字符串的Request
数据结构有一些更改。空的Method
字段一直被记录为"GET"
的别名,并且仍然如此。但是,Go 1.6 修复了一些例程,这些例程没有将空的Method
与显式的"GET"
同等对待。最值得注意的是,在以前的版本中,Client
仅在Method
显式设置为"GET"
时才遵循重定向;在 Go 1.6 中,Client
也遵循空Method
的重定向。最后,NewRequest
接受一个method
参数,该参数未被记录为允许为空。在过去的版本中,传递空的method
参数会导致Request
具有空的Method
字段。在 Go 1.6 中,生成的Request
始终具有初始化的Method
字段:如果其参数为空字符串,NewRequest
会将返回的Request
中的Method
字段设置为"GET"
。 net/http/httptest
包的ResponseRecorder
现在使用与http.Server
中相同的内容嗅探算法初始化默认的 Content-Type 头。net/url
包的Parse
在解析主机名方面现在更加严格并更符合规范。例如,主机名中的空格不再被接受。- 同样在
net/url
包中,Error
类型现在实现了net.Error
。 os
包的IsExist
、IsNotExist
和IsPermission
在查询SyscallError
时现在返回正确的结果。- 在类 Unix 系统上,当写入
os.Stdout
或os.Stderr
(更准确地说,是为文件描述符 1 或 2 打开的os.File
)由于管道损坏错误而失败时,程序将引发SIGPIPE
信号。默认情况下,这将导致程序退出;这可以通过为syscall.SIGPIPE
调用os/signal
Notify
函数来更改。对除 1 或 2 之外的文件描述符上的损坏管道的写入将简单地向调用者返回syscall.EPIPE
(可能包装在os.PathError
和/或os.SyscallError
中)。在连续 10 次写入损坏管道后引发不可捕获的SIGPIPE
信号的旧行为不再发生。 - 在
os/exec
包中,当命令以不成功的状态退出时,Cmd
的Output
方法继续返回ExitError
。如果标准错误本来会被丢弃,则返回的ExitError
现在包含失败命令的标准错误输出的前缀和后缀(目前为 32 KB),用于调试或包含在错误消息中。ExitError
的String
方法不显示捕获的标准错误;程序必须从数据结构中单独检索它。 - 在 Windows 上,
path/filepath
包的Join
函数现在正确处理基路径为相对驱动器路径的情况。例如,Join(c:,
a)
现在返回c:a
,而不是像过去版本那样返回c:\a
。这可能会影响预期不正确结果的代码。 - 在
regexp
包中,Regexp
类型始终可以安全地被并发 goroutine 使用。它使用sync.Mutex
来保护在正则表达式搜索期间使用的暂存空间缓存。一些高并发服务器在许多 goroutine 中使用相同的Regexp
时,由于该互斥锁的争用而导致性能下降。为了帮助此类服务器,Regexp
现在有一个Copy
方法,它会创建Regexp
的副本,该副本共享原始结构的大部分,但拥有自己的暂存空间缓存。两个 goroutine 可以使用不同的Regexp
副本而没有互斥锁争用。副本确实有额外的空间开销,因此只有在观察到争用时才应使用Copy
。 strconv
包增加了IsGraphic
,类似于IsPrint
。它还增加了QuoteToGraphic
、QuoteRuneToGraphic
、AppendQuoteToGraphic
和AppendQuoteRuneToGraphic
,类似于QuoteToASCII
、QuoteRuneToASCII
等。ASCII
系列转义除 ASCII 空格 (U+0020) 之外的所有空格字符。相反,Graphic
系列不转义任何 Unicode 空格字符(Zs 类别)。- 在
testing
包中,当测试调用 t.Parallel 时,该测试会暂停,直到所有非并行测试完成,然后该测试继续执行所有其他并行测试。Go 1.6 更改了此类测试的报告时间:以前的时间只计算并行执行,但现在它也计算从测试开始到调用t.Parallel
的时间。 text/template
包除了上面描述的 主要更改 之外,还包含两个次要更改。首先,它添加了一个新的ExecError
类型,用于在Execute
期间发生的任何不源于对底层写入器进行Write
的错误。调用者可以通过检查ExecError
来区分模板使用错误和 I/O 错误。其次,Funcs
方法现在检查用作FuncMap
中键的名称是否是可以在模板函数调用中出现的标识符。如果不是,Funcs
会 panic。time
包的Parse
函数一直拒绝任何大于 31 的月份日期,例如 1 月 32 日。在 Go 1.6 中,Parse
现在也拒绝非闰年的 2 月 29 日、2 月 30 日、2 月 31 日、4 月 31 日、6 月 31 日、9 月 31 日和 11 月 31 日。