Go 1.13 发行说明
Go 1.13 简介
最新的 Go 版本 1.13 在 Go 1.12 发布六个月后到来。其大部分更改都在工具链、运行时和库的实现中。一如既往,此版本保持了 Go 1 兼容性承诺。我们预计几乎所有 Go 程序都将像以前一样继续编译和运行。
从 Go 1.13 开始,go 命令默认使用 Go 模块镜像和 Google 运行的 Go 校验和数据库下载和认证模块。有关这些服务的隐私信息,请参阅 https://proxy.golang.org/privacy,有关配置详细信息,包括如何禁用这些服务器或使用不同的服务器,请参阅 go 命令文档。如果您依赖非公共模块,请参阅 配置环境的文档。
语言变化
根据 数字字面量提案,Go 1.13 支持一套更统一和现代化的数字字面量前缀。
- 二进制整数文字:前缀
0b或0B表示二进制整数文字,例如0b1011。 - 八进制整数文字:前缀
0o或0O表示八进制整数文字,例如0o660。现有由前导0后跟八进制数字表示的八进制表示法仍然有效。 - 十六进制浮点文字:现在可以使用前缀
0x或0X以十六进制格式表示浮点数的尾数,例如0x1.0p-1021。十六进制浮点数必须始终具有指数,以字母p或P后跟十进制指数表示。指数将尾数按 2 的指数幂缩放。 - 虚数字面量:虚数后缀
i现在可以与任何(二进制、十进制、十六进制)整数或浮点数字面量一起使用。 - 数字分隔符:任何数字字面量的数字现在可以使用下划线进行分隔(分组),例如
1_000_000、0b_1010_0110或3.1415_9265。下划线可以出现在任意两个数字之间或字面量前缀和第一个数字之间。
根据 带符号移位计数提案,Go 1.13 移除了 移位计数 必须为无符号的限制。此更改消除了许多人工 uint 转换的需要,这些转换仅是为了满足 << 和 >> 运算符的此(现已删除的)限制而引入的。
这些语言更改是通过对编译器以及对库包 go/scanner 和 text/scanner(数字字面量)以及 go/types(有符号移位计数)的相应内部更改来实现的。
如果您的代码使用模块并且您的 go.mod 文件指定了语言版本,请确保将其设置为至少 1.13 以访问这些语言更改。您可以通过直接编辑 go.mod 文件或运行 go mod edit -go=1.13 来实现。
移植
Go 1.13 是最后一个支持 Native Client (NaCl) 的版本。
对于 GOARCH=wasm,新的环境变量 GOWASM 接受一个以逗号分隔的实验性功能列表,二进制文件将使用这些功能进行编译。有效值在此处有文档说明。
AIX
PPC64 上的 AIX (aix/ppc64) 现在支持 cgo、外部链接以及 c-archive 和 pie 构建模式。
安卓
Go 程序现在与 Android 10 兼容。
Darwin
如 Go 1.12 发行说明中宣布的,Go 1.13 现在需要 macOS 10.11 El Capitan 或更高版本;对先前版本的支持已停止。
FreeBSD
如 Go 1.12 发行说明中宣布的,Go 1.13 现在需要 FreeBSD 11.2 或更高版本;对先前版本的支持已停止。FreeBSD 12.0 或更高版本需要一个设置了 COMPAT_FREEBSD11 选项的内核(这是默认设置)。
Illumos
Go 现在支持带有 GOOS=illumos 的 Illumos。illumos 构建标签暗示了 solaris 构建标签。
Windows
内部链接的 Windows 二进制文件指定的 Windows 版本现在是 Windows 7 而不是 NT 4.0。这已经是 Go 的最低要求版本,但可能会影响具有向后兼容模式的系统调用的行为。这些现在将按文档记载的方式运行。外部链接的二进制文件(任何使用 cgo 的程序)始终指定了更新的 Windows 版本。
工具
模块
环境变量
GO111MODULE 环境变量仍然默认为 auto,但 auto 设置现在会在当前工作目录包含或位于包含 go.mod 文件的目录下方时激活 go 命令的模块感知模式——即使当前目录在 GOPATH/src 中。此更改简化了 GOPATH/src 中现有代码的迁移以及模块感知包与非模块感知导入者的持续维护。
新的 GOPRIVATE 环境变量表示不可公开访问的模块路径。它作为较低级别的 GONOPROXY 和 GONOSUMDB 变量的默认值,这些变量提供了对哪些模块通过代理获取以及使用校验和数据库进行验证的更精细控制。
GOPROXY 环境变量 现在可以设置为以逗号分隔的代理 URL 列表或特殊令牌 direct,并且其默认值现在是 https://proxy.golang.org,direct。当将包路径解析为其包含模块时,go 命令将依次尝试列表中每个代理上的所有候选模块路径。无法访问的代理或除 404 或 410 之外的 HTTP 状态码将终止搜索,而不会咨询剩余的代理。
新的 GOSUMDB 环境变量用于识别数据库的名称(可选包括公钥和服务器 URL),该数据库用于查询尚未列在主模块 go.sum 文件中的模块的校验和。如果 GOSUMDB 不包含明确的 URL,则通过探测 GOPROXY URL 以查找指示支持校验和数据库的端点来选择 URL,如果任何代理都不支持,则回退到直接连接到指定数据库。如果 GOSUMDB 设置为 off,则不查询校验和数据库,只验证 go.sum 文件中已有的校验和。
无法访问默认代理和校验和数据库的用户(例如,由于防火墙或沙盒配置)可以通过将 GOPROXY 设置为 direct 和/或将 GOSUMDB 设置为 off 来禁用它们。可以使用 go env -w 来设置这些变量的默认值,而无需考虑平台差异。
go env -w GOPROXY=direct
go env -w GOSUMDB=off
go get
在模块感知模式下,带有 -u 标志的 go get 现在更新的模块集更小,与 GOPATH 模式下 go get -u 更新的包集更一致。go get -u 继续更新命令行上指定的模块和包,但此外只更新包含由指定包所
特别要注意的是,go get -u(不带额外参数)现在只更新当前目录中包的传递导入。要更新主模块传递导入的所有包(包括测试依赖项),请使用 go get -u all。
由于上述对 go get -u 的更改,go get 子命令不再支持 -m 标志,该标志会导致 go get 在加载包之前停止。-d 标志仍然支持,并且继续导致 go get 在下载构建指定包依赖项所需的源代码后停止。
默认情况下,模块模式下的 go get -u 只升级非测试依赖项,与 GOPATH 模式下相同。它现在也接受 -t 标志,该标志(与 GOPATH 模式下相同)会使 go get 包含命令行上指定包的
在模块感知模式下,go get 子命令现在支持版本后缀 @patch。@patch 后缀表示命名模块,或包含命名包的模块,应更新到与构建列表中找到的版本具有相同主版本和次版本的最高补丁版本。
如果一个不带版本后缀的模块作为参数传递给 go get,并且它已经需要比最新发布版本更新的版本,它将保持在更新版本。这与模块依赖项的 -u 标志的行为一致。这可以防止从预发布版本意外降级。新的版本后缀 @upgrade 明确请求此行为。@latest 明确请求最新版本,无论当前版本如何。
版本验证
从版本控制系统提取模块时,go 命令现在会对请求的版本字符串执行额外的验证。
+incompatible 版本注释绕过了在模块引入之前存在的仓库的语义导入版本控制要求。go 命令现在验证此类版本不包含显式 go.mod 文件。
go 命令现在验证 伪版本 与版本控制元数据之间的映射。具体来说:
- 版本前缀必须是
vX.0.0形式,或者派生自命名修订的祖先上的标签,或者派生自命名修订本身上包含 构建元数据 的标签。 - 日期字符串必须与修订的 UTC 时间戳匹配。
- 修订的短名称必须使用与
go命令将生成字符数相同的字符数。(对于git使用的 SHA-1 哈希,是一个 12 位的字面量。)
如果主模块中的 require 指令使用了无效的伪版本,通常可以通过将版本缩减为仅提交哈希并重新运行 go 命令(例如 go list -m all 或 go mod tidy)来纠正。例如,
require github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c
可以修改为
require github.com/docker/docker e7b5f7dbe98c
目前解析为
require github.com/docker/docker v0.7.3-0.20190319215453-e7b5f7dbe98c
如果主模块的某个传递依赖项需要无效版本或伪版本,则可以使用主模块的 go.mod 文件中的 replace 指令 将无效版本替换为有效版本。如果替换是提交哈希,它将解析为上述适当的伪版本。例如,
replace github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c => github.com/docker/docker e7b5f7dbe98c
目前解析为
replace github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c => github.com/docker/docker v0.7.3-0.20190319215453-e7b5f7dbe98c
Go 命令
go env 命令现在接受一个 -w 标志,用于设置 go 命令识别的环境变量的用户默认值,以及一个相应的 -u 标志,用于取消先前设置的默认值。通过 go env -w 设置的默认值存储在 os.UserConfigDir() 中的 go/env 文件中。
go version 命令现在接受命名可执行文件和目录的参数。当在可执行文件上调用时,go version 会打印用于构建可执行文件的 Go 版本。如果使用 -m 标志,go version 会打印可执行文件嵌入的模块版本信息(如果可用)。当在目录上调用时,go version 会打印有关目录及其子目录中包含的可执行文件的信息。
新的 go build 标志 -trimpath 从编译后的可执行文件中删除所有文件系统路径,以提高构建的可重现性。
如果传递给 go build 的 -o 标志引用现有目录,go build 现在将在该目录中为与其包参数匹配的 main 包写入可执行文件。
go build 标志 -tags 现在接受一个逗号分隔的构建标签列表,以允许在 GOFLAGS 中使用多个标签。空格分隔的形式已弃用但仍被识别并将得到维护。
go generate 现在设置 generate 构建标签,以便可以在构建过程中搜索指令但忽略文件。
正如 Go 1.12 发行说明中宣布的,不再支持仅二进制包。构建仅二进制包(用 //go:binary-only-package 注释标记)现在会导致错误。
编译器工具链
编译器采用了新的逃逸分析实现,该实现更加精确。对于大多数 Go 代码来说,这将是一个改进(换句话说,更多的 Go 变量和表达式分配在堆栈而不是堆上)。然而,这种提高的精度也可能破坏以前碰巧工作的无效代码(例如,违反 unsafe.Pointer 安全规则 的代码)。如果您发现任何似乎相关的回归,可以使用 go build -gcflags=all=-newescape=false 重新启用旧的逃逸分析通道。使用旧逃逸分析的选项将在未来的版本中删除。
编译器不再向 go_asm.h 文件发出浮点或复杂常量。这些常量始终以不能在汇编代码中用作数字常量的形式发出。
汇编器
汇编器现在支持 ARM v8.1 中引入的许多原子指令。
gofmt
gofmt(以及 go fmt)现在将数字字面量前缀和指数规范化为小写字母,但保留十六进制数字不变。这在使用新的八进制前缀(0O 变为 0o)时提高了可读性,并且重写一致地应用。gofmt 现在还从十进制整数虚数字面量中删除了不必要的前导零。(为了向后兼容,以 0 开头的整数虚数字面量被视为十进制数,而不是八进制数。删除多余的前导零可以避免潜在的混淆。)例如,0B1010、0XabcDEF、0O660、1.2E3 和 01i 在应用 gofmt 后变为 0b1010、0xabcDEF、0o660、1.2e3 和 1i。
godoc 和 go doc
godoc 网络服务器不再包含在主二进制发行版中。要在本地运行 godoc 网络服务器,请先手动安装它。
go get golang.org/x/tools/cmd/godoc
godoc
go doc 命令现在总是包含输出中的包子句,除了命令。这取代了以前使用启发式方法,导致包子句在某些条件下被省略的行为。
运行时
超出范围的 panic 消息现在包含超出范围的索引以及切片的长度(或容量)。例如,对长度为 1 的切片执行 s[3] 将 panic 并显示“runtime error: index out of range [3] with length 1”。
此版本将大多数 defer 的使用性能提高了 30%。
运行时现在更积极地将内存返回给操作系统,使其可用于共租用应用程序。以前,运行时在堆大小急剧增加后可能会保留内存五分钟或更长时间。现在,它将在堆缩小后立即开始返回内存。然而,在包括 Linux 在内的许多操作系统上,操作系统本身会惰性地回收内存,因此在系统处于内存压力下之前,进程 RSS 不会减少。
标准库
TLS 1.3
正如 Go 1.12 中宣布的,Go 1.13 默认在 crypto/tls 包中启用 TLS 1.3 支持。可以通过将值 tls13=0 添加到 GODEBUG 环境变量来禁用它。此选择退出将在 Go 1.14 中删除。
有关重要的兼容性信息,请参阅Go 1.12 发行说明。
crypto/ed25519
新的 crypto/ed25519 包实现了 Ed25519 签名方案。此功能以前由 golang.org/x/crypto/ed25519 包提供,该包在与 Go 1.13+ 一起使用时成为 crypto/ed25519 的包装器。
错误包装
Go 1.13 包含对错误包装的支持,首次在 错误值提案 中提出,并在相关问题上进行了讨论。
错误 e 可以通过提供一个返回 w 的 Unwrap 方法来w。程序可以同时访问 e 和 w,允许 e 为 w 提供额外上下文或重新解释它,同时仍然允许程序根据 w 做出决策。
为了支持包装,fmt.Errorf 现在有一个用于创建包装错误的 %w 动词,并且 errors 包中有三个新函数(errors.Unwrap、errors.Is 和 errors.As)简化了对包装错误的解包和检查。
有关更多信息,请阅读 errors 包文档,或参阅 错误值常见问题解答。很快也会有一篇博客文章。
对库的微小更改
与往常一样,库中有各种微小的更改和更新,这些都是在遵守 Go 1 兼容性承诺的前提下进行的。
bytes
新的 ToValidUTF8 函数返回给定字节切片的副本,其中每个无效的 UTF-8 字节序列运行都替换为给定的切片。
context
通过 WithValue 返回的上下文的格式不再依赖于 fmt,并且不会以相同的方式进行字符串化。依赖精确的先前字符串化的代码可能会受到影响。
crypto/tls
对 SSL 3.0 版本 (SSLv3) 的支持 现已弃用,并将在 Go 1.14 中删除。请注意,SSLv3 是早于 TLS 的 加密损坏 协议。
SSLv3 总是默认禁用,除了 Go 1.12 中,当时它被错误地在服务器端默认启用。现在它又默认禁用了。(SSLv3 从未在客户端支持。)
TLS 1.2 和 1.3 版本现在支持 Ed25519 证书。
crypto/x509
根据 RFC 8410,证书和证书请求现在支持 Ed25519 密钥,并且 ParsePKCS8PrivateKey、MarshalPKCS8PrivateKey 和 ParsePKIXPublicKey 函数也支持 Ed25519 密钥。
系统根的搜索路径现在包括 /etc/ssl/cert.pem,以支持 Alpine Linux 3.7+ 中的默认位置。
database/sql
新的 NullTime 类型表示一个可能为空的 time.Time。
新的 NullInt32 类型表示一个可能为空的 int32。
debug/dwarf
如果 Data.Type 方法在类型图中遇到未知 DWARF 标签,它将不再 panic。相反,它用一个 UnsupportedType 对象表示该类型组件。
errors
新的函数 As 在给定错误的链(包装错误的序列)中查找第一个与给定目标类型匹配的错误,如果找到,则将目标设置为该错误值。
新的函数 Is 报告给定错误值是否与另一个错误链中的错误匹配。
新的函数 Unwrap 返回对给定错误调用 Unwrap 的结果(如果存在)。
fmt
打印动词 %x 和 %X 现在以十六进制表示法格式化浮点数和复数,分别使用小写和大写。
新的打印动词 %O 以八进制格式化整数,发出 0o 前缀。
扫描器现在接受十六进制浮点值、数字分隔下划线以及前导 0b 和 0o 前缀。有关详细信息,请参阅语言更改。
Errorf 函数有一个新的动词 %w,其操作数必须是一个错误。从 Errorf 返回的错误将有一个 Unwrap 方法,该方法返回 %w 的操作数。
go/scanner
扫描器已更新以识别新的 Go 数字字面量,特别是带 0b/0B 前缀的二进制字面量、带 0o/0O 前缀的八进制字面量以及带十六进制尾数的浮点数。虚数后缀 i 现在可以与任何数字字面量一起使用,下划线可以作为数字分隔符用于分组。有关详细信息,请参阅语言更改。
go/types
类型检查器已更新,以遵循整数移位的新规则。有关详细信息,请参阅语言更改。
html/template
当使用 <script> 标签并将“module”设置为类型属性时,代码现在将被解释为 JavaScript 模块脚本。
log
新的 Writer 函数返回标准日志记录器的输出目标。
math/big
新的 Rat.SetUint64 方法将 Rat 设置为 uint64 值。
对于 Float.Parse,如果基数为 0,则数字之间可以使用下划线以提高可读性。有关详细信息,请参阅语言更改。
对于 Int.SetString,如果基数为 0,则数字之间可以使用下划线以提高可读性。有关详细信息,请参阅语言更改。
Rat.SetString 现在接受非十进制浮点表示。
math/bits
Add、Sub、Mul、RotateLeft 和 ReverseBytes 的执行时间现在保证与输入无关。
net
在 Unix 系统上,如果 resolv.conf 中设置了 use-vc,则使用 TCP 进行 DNS 解析。
新字段 ListenConfig.KeepAlive 指定监听器接受的网络连接的 keep-alive 周期。如果此字段为 0(默认),将启用 TCP keep-alive。要禁用它们,请将其设置为负值。
请注意,由于 keep-alive 超时而关闭的连接上的 I/O 返回的错误将具有一个 Timeout 方法,该方法在被调用时返回 true。这使得 keep-alive 错误难以与由于 SetDeadline 方法和类似方法设置的截止日期未达到而返回的错误区分开来。使用截止日期并通过 Timeout 方法或 os.IsTimeout 检查截止日期的代码可能希望禁用 keep-alive,或者使用 errors.Is(syscall.ETIMEDOUT)(在 Unix 系统上),该方法对于 keep-alive 超时返回 true,对于截止日期超时返回 false。
net/http
新字段 Transport.WriteBufferSize 和 Transport.ReadBufferSize 允许指定 Transport 的写入和读取缓冲区大小。如果任一字段为零,则使用默认大小 4KB。
新字段 Transport.ForceAttemptHTTP2 控制在提供非零 Dial、DialTLS 或 DialContext 函数或 TLSClientConfig 时是否启用 HTTP/2。
Transport.MaxConnsPerHost 现在在 HTTP/2 下正常工作。
TimeoutHandler 的 ResponseWriter 现在实现了 Pusher 接口。
已添加状态码 103 "Early Hints"。
Transport 现在使用 Request.Body 的 io.ReaderFrom 实现(如果可用),以优化写入主体。
在遇到不支持的传输编码时,http.Server 现在返回“501 Unimplemented”状态,这是 HTTP 规范 RFC 7230 第 3.3.1 节 所强制要求的。
新的 Server 字段 BaseContext 和 ConnContext 允许更精细地控制提供给请求和连接的 Context 值。
http.DetectContentType 现在正确检测 RAR 签名,并且现在还可以检测 RAR v5 签名。
添加了一个新函数 NewRequestWithContext,它接受一个 Context 来控制创建的传出 Request 的整个生命周期,适用于与 Client.Do 和 Transport.RoundTrip 一起使用。
当服务器使用 "408 Request Timeout" 响应优雅地关闭空闲连接时,Transport 不再记录错误。
os
新的 UserConfigDir 函数返回用于用户特定配置数据的默认目录。
如果一个 File 使用 O_APPEND 标志打开,它的 WriteAt 方法将总是返回错误。
os/exec
在 Windows 上,Cmd 的环境始终继承父进程的 %SYSTEMROOT% 值,除非 Cmd.Env 字段包含其显式值。
reflect
新的 Value.IsZero 方法报告 Value 是否是其类型的零值。
MakeFunc 函数现在允许对返回值进行赋值转换,而不是要求精确的类型匹配。当返回的类型是接口类型,而实际返回的值是实现该类型的具体值时,这特别有用。
runtime
Traceback、runtime.Caller 和 runtime.Callers 现在将初始化 PKG 全局变量的函数称为 PKG.init,而不是 PKG.init.ializers。
strconv
对于 strconv.ParseFloat、strconv.ParseInt 和 strconv.ParseUint,如果基数为 0,则数字之间可以使用下划线以提高可读性。有关详细信息,请参阅语言更改。
strings
新的 ToValidUTF8 函数返回给定字符串的副本,其中每个无效的 UTF-8 字节序列运行都替换为给定的字符串。
sync
Mutex.Lock、Mutex.Unlock、RWMutex.Lock、RWMutex.RUnlock 和 Once.Do 的快速路径现在已在其调用方中内联。对于 amd64 上的无竞争情况,这些更改使 Once.Do 速度提高一倍,Mutex/RWMutex 方法速度提高高达 10%。
大型 Pool 不再增加停止-世界暂停时间。
Pool 在每次 GC 后不再需要完全重新填充。它现在在 GC 期间保留一些对象,而不是释放所有对象,从而减少了 Pool 重度使用者的负载峰值。
syscall
Darwin 构建中已删除 _getdirentries64 的使用,以允许 Go 二进制文件上传到 macOS App Store。
Windows 版 SysProcAttr 中引入了新的 ProcessAttributes 和 ThreadAttributes 字段,用于在新进程创建时公开安全设置。
在 Windows 上,Chmod 零模式不再返回 EINVAL。
类型为 Errno 的值可以使用 errors.Is 与 os 包中的错误值(例如 ErrExist)进行测试。
syscall/js
TypedArrayOf 已被 CopyBytesToGo 和 CopyBytesToJS 取代,用于在字节切片和 Uint8Array 之间复制字节。
testing
运行基准测试时,B.N 不再进行舍入。
新的方法 B.ReportMetric 允许用户报告自定义基准指标并覆盖内置指标。
测试标志现在注册在新的 Init 函数中,该函数由生成的测试 main 函数调用。因此,测试标志现在只在运行测试二进制文件时注册,并且在包初始化期间调用 flag.Parse 的包可能会导致测试失败。
text/scanner
扫描器已更新以识别新的 Go 数字字面量,特别是带 0b/0B 前缀的二进制字面量、带 0o/0O 前缀的八进制字面量以及带十六进制尾数的浮点数。此外,新的 AllowDigitSeparators 模式允许数字字面量包含下划线作为数字分隔符(默认情况下为向后兼容性而禁用)。有关详细信息,请参阅语言更改。
text/template
新的 切片函数 返回将其第一个参数按后续参数切片的结果。
time
新的 Duration 方法 Microseconds 和 Milliseconds 返回持续时间作为其各自命名单位的整数计数。
unicode
unicode 包和整个系统中的相关支持已从 Unicode 10.0 升级到 Unicode 11.0,该版本增加了 684 个新字符,包括七个新脚本和 66 个新表情符号。