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
get
、go
list
和 go
mod
download
之类的命令的行为就像在一个具有初始空要求的模块中一样。在此模式下,go
env
GOMOD
报告系统的空设备 (/dev/null
或 NUL
)。
现在可以安全地并发调用下载和提取模块的 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.CallersFrames
和 runtime.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 启用)。
godoc
和 go
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.Caller
和runtime.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
Reader
的UnreadRune
和UnreadByte
方法现在将在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
fmt
现在按键排序顺序打印映射以简化测试。排序规则是
- 在适用情况下,nil 比较小
- int、float 和 string 按<排序
- NaN 比非 NaN float 小
- bool 将 false 放在 true 之前比较
- Complex 先比较实部,再比较虚部
- 指针按机器地址比较
- 通道值按机器地址比较
- 结构体依次比较每个字段
- 数组依次比较每个元素
- 接口值首先按描述具体类型的
reflect.Type
进行比较,然后按前面规则中描述的具体值进行比较。
在打印映射时,以前将像NaN
这样的非自反键值显示为<nil>
。从本版本开始,将打印正确的值。
go/doc
为了解决cmd/doc
中的一些未决问题,此包有一个新的Mode
位PreserveAST
,它控制是否清除 AST 数据。
go/token
File
类型有一个新的LineStart
字段,它返回给定行的起始位置。这在偶尔处理非 Go 文件(如汇编)但希望使用token.Pos
机制来识别文件位置的程序中特别有用。
image
RegisterFormat
函数现在可以安全地并发使用。
image/png
颜色数少于 16 种的调色板图像现在可以编码为更小的输出。
io
新的StringWriter
接口包装了WriteString
函数。
math
Sin
、Cos
、Tan
和Sincos
函数现在对巨大的参数应用 Payne-Hanek 范围缩减。这会产生更准确的答案,但它们不会与早期版本中的结果完全相同。
math/bits
新的扩展精度运算Add
、Sub
、Mul
和Div
在uint
、uint32
和uint64
版本中可用。
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
的底层Transport
的CloseIdleConnections
(如果存在)。
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
Parse
、ParseRequestURI
和URL.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
方法返回构建器底层字节切片的容量。
字符映射函数 Map
、Title
、ToLower
、ToLowerSpecial
、ToTitle
、ToTitleSpecial
、ToUpper
和 ToUpperSpecial
现在始终保证返回有效的 UTF-8。在早期版本中,如果输入是无效的 UTF-8 但不需要应用字符替换,则这些例程会错误地返回未修改的无效 UTF-8。
syscall
FreeBSD 12 现在支持 64 位 inode。一些类型已相应调整。
Unix 套接字(AF_UNIX
)地址族现在受兼容版本的 Windows 支持。
为 Windows 引入了新的函数 Syscall18
,允许最多使用 18 个参数进行调用。
syscall/js
Callback
类型和 NewCallback
函数已重命名;它们现在分别称为 Func
和 FuncOf
。这是一个重大更改,但 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 现在会被捕获并作为错误由 Execute
或 ExecuteTemplate
方法返回。
time
$GOROOT/lib/time/zoneinfo.zip
中的时区数据库已更新至 2018i 版本。请注意,仅当操作系统未提供时区数据库时才会使用此 ZIP 文件。
unsafe
将 nil unsafe.Pointer
转换为 uintptr
并通过算术运算转换回是不合法的。(这本来就是非法的,但现在会导致编译器行为异常。)