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-shared
和 c-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 包的信息,因此它能够构建同样适用于替代构建系统(如 Bazel 和 Buck)的分析工具。
构建缓存要求
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) {
}
}
这已被 gccgo
和 go/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 命令
现在可以使用环境变量GOFLAGS
为go
命令设置默认标志。这在某些情况下很有用。由于 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
pkg
或go
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.Sign
、rsa.EncryptPKCS1v15
和rsa.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
。
扩展密钥使用限制仅在它们出现在VerifyOptions
的KeyUsages
字段中时才被检查,而不是始终被检查。这与 Go 1.9 及更早版本的行为相匹配。
SystemCertPool
返回的值现在被缓存,并且可能无法反映调用之间系统更改。
debug/elf
encoding/asn1
Marshal
和Unmarshal
现在支持字段的“私有”类注释。
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.RawConn
的Read
和Write
方法现在在 Windows 上可以正常工作。
net
包现在在 Linux 上使用splice
系统调用(在TCPConn.ReadFrom
中,由io.Copy
调用)在 TCP 连接之间复制数据时。结果是更快的、更高效的 TCP 代理。
TCPConn.File
、UDPConn.File
、UnixConn.File
和IPConn.File
方法不再将返回的*os.File
置于阻塞模式。
net/http
Transport
类型具有一个新的MaxConnsPerHost
选项,允许限制每个主机的最大连接数。
Cookie
类型新增了一个 SameSite
字段(也是一个新类型,命名为 SameSite
),用于表示最近大多数浏览器支持的新 cookie 属性。net/http
的 Transport
本身不使用 SameSite
属性,但该包支持解析和序列化该属性以供浏览器使用。
在调用 Shutdown
或 Close
之后,不再允许重用 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 上,Faccessat
的 flags
参数现在与 glibc 中的实现相同。在早期的 Go 版本中,忽略了 flags
参数。
在 Linux 上,Fchmodat
的 flags
参数现在已通过验证。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
)。