Go 1.12 发行说明

Go 1.12 简介

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

语言更改

语言规范没有任何更改。

端口

现在在 linux/arm64 上支持竞态检测器。

Go 1.12 是最后一个支持 FreeBSD 10.x 的版本,FreeBSD 10.x 已经达到生命周期结束。Go 1.13 将需要 FreeBSD 11.2+ 或 FreeBSD 12.0+。FreeBSD 12.0+ 需要具有 COMPAT_FREEBSD11 选项设置的内核(这是默认设置)。

cgo 现在在 linux/ppc64 上受支持。

hurd 现在是 GOOS 的一个已识别值,保留供 GNU/Hurd 系统与 gccgo 一起使用。

Windows

Go 的新 windows/arm 端口支持在 32 位 ARM 芯片(如 Raspberry Pi 3)上的 Windows 10 IoT Core 上运行 Go。

AIX

Go 现在支持 POWER8 架构 (aix/ppc64) 上的 AIX 7.2 及更高版本。外部链接、cgo、pprof 和竞态检测器尚不受支持。

Darwin

Go 1.12 是最后一个将在 macOS 10.10 Yosemite 上运行的版本。Go 1.13 将需要 macOS 10.11 El Capitan 或更高版本。

在 Darwin 上进行系统调用时,现在使用 libSystem,确保与未来版本的 macOS 和 iOS 向后兼容。切换到 libSystem 触发了对私有 API 使用情况的额外 App Store 检查。由于它被认为是私有的,因此 syscall.Getdirentries 现在在 iOS 上始终以 ENOSYS 失败。此外,syscall.Setrlimit 在历史上成功的地方报告 invalid argument。这些后果并非特定于 Go,用户应期望与 libSystem 的实现的行为一致。

工具

go tool vet 不再受支持

go vet 命令已重写,用作一系列不同源代码分析工具的基础。有关详细信息,请参阅 golang.org/x/tools/go/analysis 软件包。一个副作用是 go tool vet 不再受支持。必须更改使用 go tool vet 的外部工具以使用 go vet。使用 go vet 而不是 go tool vet 应该适用于所有受支持的 Go 版本。

作为此更改的一部分,实验性 -shadow 选项不再可用于 go vet。现在可以使用以下方法检查变量隐藏:

go get -u golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
go vet -vettool=$(which shadow)

教程

Go 教程不再包含在主二进制发行版中。要本地运行教程,而不是运行 go tool tour,请手动安装它

go get -u golang.org/x/tour
tour

构建缓存要求

现在需要 构建缓存 作为消除 $GOPATH/pkg 的一个步骤。设置环境变量 GOCACHE=off 将导致写入缓存的 go 命令失败。

仅二进制软件包

Go 1.12 是最后一个将支持仅二进制软件包的版本。

Cgo

Go 1.12 将把 C 类型 EGLDisplay 转换为 Go 类型 uintptr。此更改类似于 Go 1.10 及更高版本如何处理 Darwin 的 CoreFoundation 和 Java 的 JNI 类型。有关更多信息,请参阅 cgo 文档

在使用 Cgo 的软件包中,不再接受混淆的 C 名称。请改用 Cgo 名称。例如,使用已记录的 cgo 名称 C.char 而不是 cgo 生成的混淆名称 _Ctype_char

模块

GO111MODULE 设置为 on 时,go 命令现在支持在模块目录之外执行模块感知操作,前提是这些操作不需要解析相对于当前目录的导入路径或显式编辑 go.mod 文件。诸如 go getgo listgo mod download 之类的命令的行为就像在一个具有初始空要求的模块中一样。在此模式下,go env GOMOD 报告系统的空设备 (/dev/nullNUL)。

现在可以安全地并发调用下载和提取模块的 go 命令。模块缓存 (GOPATH/pkg/mod) 必须驻留在支持文件锁定的文件系统中。

go.mod 文件中的 go 指令现在指示该模块内文件使用的语言版本。如果不存在现有版本,它将设置为当前版本 (go 1.12)。如果模块的 go 指令指定的版本高于正在使用的工具链,则 go 命令将尝试构建这些软件包,并且仅在构建失败时才会注意到不匹配。

go 指令的这种更改意味着,如果您使用 Go 1.12 构建模块,从而在 go.mod 文件中记录 go 1.12,则尝试使用 Go 1.11 到 Go 1.11.3 构建同一模块时将出现错误。Go 1.11.4 或更高版本将可以正常工作,Go 1.11 之前的版本也可以正常工作。如果您必须使用 Go 1.11 到 1.11.3,则可以通过将语言版本设置为 1.11(使用 Go 1.12 go 工具,通过 go mod edit -go=1.11)来避免此问题。

当无法使用活动模块解析导入时,go 命令现在将在咨询模块缓存和通常的网络源之前尝试使用主模块的 replace 指令中提到的模块。如果找到匹配的替换,但 replace 指令未指定版本,则 go 命令将使用从零 time.Time 派生的伪版本(例如 v0.0.0-00010101000000-000000000000)。

编译器工具链

编译器的活动变量分析已改进。这意味着在此版本中,终结器可能比以前版本更早执行。如果这是一个问题,请考虑适当地添加 runtime.KeepAlive 调用。

现在默认情况下,更多函数有资格进行内联,包括仅调用另一个函数的函数。这种额外的内联使得使用 runtime.CallersFrames 而不是直接迭代 runtime.Callers 的结果变得更加重要。

// Old code which no longer works correctly (it will miss inlined call frames).
var pcs [10]uintptr
n := runtime.Callers(1, pcs[:])
for _, pc := range pcs[:n] {
    f := runtime.FuncForPC(pc)
    if f != nil {
        fmt.Println(f.Name())
    }
}
// New code which will work correctly.
var pcs [10]uintptr
n := runtime.Callers(1, pcs[:])
frames := runtime.CallersFrames(pcs[:n])
for {
    frame, more := frames.Next()
    fmt.Println(frame.Function)
    if !more {
        break
    }
}

编译器为实现方法表达式而生成的包装器不再由 runtime.CallersFramesruntime.Stack 报告。它们也不会在 panic 堆栈跟踪中打印。此更改使 gc 工具链与 gccgo 工具链保持一致,后者已从堆栈跟踪中省略了此类包装器。这些 API 的客户端可能需要调整以适应缺少的帧。对于必须在 1.11 和 1.12 版本之间互操作的代码,您可以将方法表达式 x.M 替换为函数字面量 func (...) { x.M(...) }

编译器现在接受 -lang 标志来设置要使用的 Go 语言版本。例如,-lang=go1.8 会导致编译器在程序使用类型别名时发出错误,类型别名是在 Go 1.9 中添加的。Go 1.12 之前做出的语言更改并非始终得到强制执行。

编译器工具链现在使用不同的约定来调用 Go 函数和汇编函数。这对于用户来说应该是不可见的,除了同时跨越 Go 和汇编以及跨越包边界的调用。如果链接导致出现类似“relocation target not defined for ABIInternal (but is defined for ABI0)”的错误,请参阅 ABI 设计文档的 兼容性部分

编译器生成的 DWARF 调试信息有了很多改进,包括对参数打印和变量位置信息的改进。

Go 程序现在还在 linux/arm64 上维护堆栈帧指针,以供 perf 等性能分析工具使用。帧指针维护会产生很小的运行时开销,该开销会发生变化,但平均约为 3%。要构建不使用帧指针的工具链,请在运行 make.bash 时设置 GOEXPERIMENT=noframepointer

已删除过时的“安全”编译器模式(由 -u gcflag 启用)。

godocgo doc

在 Go 1.12 中,godoc 不再具有命令行界面,而只是一个 Web 服务器。用户应改为使用 go doc 获取命令行帮助输出。Go 1.12 是最后一个将包含 godoc Web 服务器的版本;在 Go 1.13 中,它将通过 go get 获得。

go doc 现在支持 -all 标志,这将导致它打印所有导出的 API 及其文档,就像 godoc 命令行过去所做的那样。

go doc 现在还包括 -src 标志,这将显示目标的源代码。

跟踪

跟踪工具现在支持绘制变异器利用率曲线,包括与执行跟踪的交叉引用。这些对于分析垃圾回收器对应用程序延迟和吞吐量的影响非常有用。

汇编器

arm64上,平台寄存器已从R18重命名为R18_PLATFORM,以防止意外使用,因为操作系统可能会选择保留此寄存器。

运行时

Go 1.12 显著提高了当堆的大部分仍然存活时扫描的性能。这减少了垃圾回收后立即的分配延迟。

Go 运行时现在更积极地将内存释放回操作系统,尤其是在响应无法重用现有堆空间的大型分配时。

Go 运行时的计时器和截止日期代码更快,并且随着 CPU 数量的增加而更好地扩展。特别是,这提高了操作网络连接截止日期的性能。

在 Linux 上,运行时现在使用MADV_FREE释放未使用的内存。这更有效,但可能会导致报告的 RSS 更高。内核将在需要时回收未使用的数据。要恢复到 Go 1.11 的行为(MADV_DONTNEED),请设置环境变量GODEBUG=madvdontneed=1

GODEBUG环境变量中添加cpu.extension=off现在会禁用标准库和运行时中可选 CPU 指令集扩展的使用。Windows 上尚不支持此功能。

Go 1.12 通过修复对大型堆分配的过度计数来提高内存配置文件的准确性。

回溯、runtime.Callerruntime.Callers不再包含编译器生成的初始化函数。在全局变量的初始化期间执行回溯现在将显示一个名为PKG.init.ializers的函数。

标准库

TLS 1.3

Go 1.12 在crypto/tls包中添加了对 TLS 1.3 的可选支持,如RFC 8446中所指定。可以通过在GODEBUG环境变量中添加值tls13=1来启用它。它将在 Go 1.13 中默认启用。

要协商 TLS 1.3,请确保您没有在Config中设置显式的MaxVersion,并在设置了环境变量GODEBUG=tls13=1的情况下运行您的程序。

除了ConnectionState中的TLSUnique和重新协商之外,所有 TLS 1.2 功能都可以在 TLS 1.3 中使用,并提供相同或更好的安全性和性能。请注意,即使 TLS 1.3 向后兼容以前的版本,某些旧系统在尝试协商它时也可能无法正常工作。安全性不足的 RSA 证书密钥(包括 512 位密钥)将无法与 TLS 1.3 一起使用。

TLS 1.3 密码套件不可配置。所有支持的密码套件都是安全的,如果在Config中设置了PreferServerCipherSuites,则首选项顺序将基于可用的硬件。

早期数据(也称为“0-RTT 模式”)当前不支持作为客户端或服务器。此外,Go 1.12 服务器不支持在客户端发送意外的早期数据时跳过它。由于 TLS 1.3 0-RTT 模式涉及客户端保持有关哪些服务器支持 0-RTT 的状态,因此 Go 1.12 服务器不能成为负载平衡池的一部分,其中某些其他服务器确实支持 0-RTT。如果将域从支持 0-RTT 的服务器切换到 Go 1.12 服务器,则必须至少在切换之前发出的会话票证的生命周期内禁用 0-RTT,以确保不间断操作。

在 TLS 1.3 中,客户端是握手时最后一个说话的人,因此如果它导致服务器发生错误,则客户端将在第一次Read时返回该错误,而不是通过Handshake返回。例如,如果服务器拒绝客户端证书,则会出现这种情况。类似地,会话票证现在是握手后的消息,因此客户端仅在其第一次Read时才会收到它们。

库的次要更改

与往常一样,库中存在各种次要更改和更新,这些更改和更新是在 Go 1兼容性承诺的指导下进行的。

bufio

ReaderUnreadRuneUnreadByte方法现在将在Peek之后调用时返回错误。

bytes

新函数ReplaceAll返回字节切片的副本,其中所有不重叠的值实例都被另一个值替换。

指向零值Reader的指针现在在功能上等效于NewReader(nil)。在 Go 1.12 之前,前者并非在所有情况下都可以替代后者。

crypto/rand

Reader.Read第一次阻塞超过 60 秒等待从内核读取熵时,现在会向标准错误打印警告。

在 FreeBSD 上,Reader现在使用getrandom系统调用(如果可用),否则使用/dev/urandom

crypto/rc4

此版本删除了汇编实现,只保留了纯 Go 版本。Go 编译器生成的代码略好或略差,具体取决于确切的 CPU。RC4 不安全,仅应用于与旧系统的兼容性。

crypto/tls

如果客户端发送的初始消息看起来不像 TLS,服务器将不再回复警报,并且它将在RecordHeaderError的新字段Conn中公开底层的net.Conn

database/sql

现在可以通过将*Rows值传递给Row.Scan方法来获取查询游标。

expvar

新的Delete方法允许从Map中删除键/值对。

fmt

现在按键排序顺序打印映射以简化测试。排序规则是

在打印映射时,以前将像NaN这样的非自反键值显示为<nil>。从本版本开始,将打印正确的值。

go/doc

为了解决cmd/doc中的一些未决问题,此包有一个新的ModePreserveAST,它控制是否清除 AST 数据。

go/token

File类型有一个新的LineStart字段,它返回给定行的起始位置。这在偶尔处理非 Go 文件(如汇编)但希望使用token.Pos机制来识别文件位置的程序中特别有用。

image

RegisterFormat函数现在可以安全地并发使用。

image/png

颜色数少于 16 种的调色板图像现在可以编码为更小的输出。

io

新的StringWriter接口包装了WriteString函数。

math

SinCosTanSincos函数现在对巨大的参数应用 Payne-Hanek 范围缩减。这会产生更准确的答案,但它们不会与早期版本中的结果完全相同。

math/bits

新的扩展精度运算AddSubMulDivuintuint32uint64版本中可用。

net

Dialer.DualStack设置现在被忽略并弃用;RFC 6555 快速回退(“快乐眼球”)现在默认启用。要禁用,请将Dialer.FallbackDelay设置为负值。

类似地,如果Dialer.KeepAlive为零,则 TCP 保活现在默认启用。要禁用,请将其设置为负值。

在 Linux 上,现在在从UnixConn复制到TCPConn时使用splice系统调用

net/http

HTTP 服务器现在会拒绝错误地定向到 HTTPS 服务器的 HTTP 请求,并使用纯文本“400 Bad Request”响应。

新的Client.CloseIdleConnections方法调用Client的底层TransportCloseIdleConnections(如果存在)。

Transport不再拒绝声明 HTTP 尾部但未使用分块编码的 HTTP 响应。相反,现在只是忽略声明的尾部。

Transport不再像在 Go 1.10 和 Go 1.11 中那样严格地处理从 HTTP/2 服务器宣传的MAX_CONCURRENT_STREAMS值。默认行为现在恢复到 Go 1.9 中的方式:每个到服务器的连接最多可以有MAX_CONCURRENT_STREAMS个请求处于活动状态,然后根据需要创建新的 TCP 连接。在 Go 1.10 和 Go 1.11 中,http2包将阻塞并等待请求完成,而不是创建新的连接。要恢复更严格的行为,请直接导入golang.org/x/net/http2包,并将Transport.StrictMaxConcurrentStreams设置为true

net/url

ParseParseRequestURIURL.Parse现在对包含 ASCII 控制字符的 URL 返回错误,其中包括 NULL、制表符和换行符。

net/http/httputil

ReverseProxy现在自动代理 WebSocket 请求。

os

新的ProcessState.ExitCode方法返回进程的退出代码。

ModeCharDevice已添加到ModeType位掩码中,允许在使用ModeType掩盖FileMode时恢复ModeDevice | ModeCharDevice

新函数UserHomeDir返回当前用户的 home 目录。

RemoveAll现在支持大多数 Unix 系统上超过 4096 个字符的路径。

File.Sync 现在在 macOS 上使用 F_FULLFSYNC 来正确地将文件内容刷新到永久存储。这可能会导致该方法运行速度比以前版本慢。

File 现在支持一个 SyscallConn 方法,该方法返回一个 syscall.RawConn 接口值。这可以用来在底层文件描述符上调用特定于系统的操作。

path/filepath

IsAbs 函数现在在传递 Windows 上的保留文件名(例如 NUL)时返回 true。 保留名称列表。

reflect

新的 MapIter 类型是用于遍历 map 的迭代器。此类型通过 Value 类型的新的 MapRange 方法公开。这遵循与 range 语句相同的迭代语义,使用 Next 来推进迭代器,以及 Key/Value 来访问每个条目。

regexp

Copy 不再需要避免锁争用,因此它已添加了部分弃用注释。如果使用 Copy 的原因是为了创建两个具有不同 Longest 设置的副本,则它可能仍然适用。

runtime/debug

新的 BuildInfo 类型公开了从正在运行的二进制文件中读取的构建信息,仅在使用模块支持构建的二进制文件中可用。这包括主包路径、主模块信息和模块依赖项。此类型通过 ReadBuildInfo 函数在 BuildInfo 上提供。

strings

新函数 ReplaceAll 返回字符串的副本,其中所有不重叠的值实例都被另一个值替换。

指向零值 Reader 的指针现在在功能上等同于 NewReader(nil)。在 Go 1.12 之前,前者并非在所有情况下都可以作为后者的替代品。

新的 Builder.Cap 方法返回构建器底层字节切片的容量。

字符映射函数 MapTitleToLowerToLowerSpecialToTitleToTitleSpecialToUpperToUpperSpecial 现在始终保证返回有效的 UTF-8。在早期版本中,如果输入是无效的 UTF-8 但不需要应用字符替换,则这些例程会错误地返回未修改的无效 UTF-8。

syscall

FreeBSD 12 现在支持 64 位 inode。一些类型已相应调整。

Unix 套接字(AF_UNIX)地址族现在受兼容版本的 Windows 支持。

为 Windows 引入了新的函数 Syscall18,允许最多使用 18 个参数进行调用。

syscall/js

Callback 类型和 NewCallback 函数已重命名;它们现在分别称为 FuncFuncOf。这是一个重大更改,但 WebAssembly 支持仍处于实验阶段,尚未受 Go 1 兼容性承诺 的约束。任何使用旧名称的代码都需要更新。

如果某个类型实现了新的 Wrapper 接口,则 ValueOf 将使用它来返回该类型的 JavaScript 值。

Value 的含义已更改。它现在表示 JavaScript undefined 值,而不是数字零。这是一个重大更改,但 WebAssembly 支持仍处于实验阶段,尚未受 Go 1 兼容性承诺 的约束。任何依赖于零 Value 表示数字零的代码都需要更新。

新的 Value.Truthy 方法报告给定值的 JavaScript“真值”

testing

-benchtime 标志现在支持设置显式迭代次数,而不是在值以“x”结尾时设置时间。例如,-benchtime=100x 将运行基准测试 100 次。

text/template

执行模板时,错误中的长上下文值不再被截断。

执行 "tmpl" at <.very.deep.context.v...>: map has no entry for key "notpresent"

现在是

执行 "tmpl" at <.very.deep.context.value.notpresent>: map has no entry for key "notpresent"

如果模板调用的用户定义函数发生 panic,则该 panic 现在会被捕获并作为错误由 ExecuteExecuteTemplate 方法返回。

time

$GOROOT/lib/time/zoneinfo.zip 中的时区数据库已更新至 2018i 版本。请注意,仅当操作系统未提供时区数据库时才会使用此 ZIP 文件。

unsafe

将 nil unsafe.Pointer 转换为 uintptr 并通过算术运算转换回是不合法的。(这本来就是非法的,但现在会导致编译器行为异常。)