最新Go版本1.13在Go v1.12发布六个月后推出,它的大部分变化在于工具链、运行时和库的实现,该版本保存与Go 1的兼容性承诺。从Go 1.13开始,go命令默认使用Go module mirror和Go checksum database来下载和认证modules。本文将介绍Go1.13的变化及新特
语言的变化
根据数字文字提案,Go1.13支持更统一和现代化的数字文字前缀
Binary integer literals 前缀0b或0B表示二进制整数字面值,例如:0b1011
Octal integer literals 前缀0o或0O表示八进制整数字面值,例如:0o660。由前导0后跟八进制数字指示的现有八进制表示法仍然有效
Hexadecimal floating point literals 前缀0x或0X可以用来表示十六进制浮点数的尾数,例如:0x1.0p-1021。十六进制的浮点数必须带有指数,用p或P表示后面跟上十进制的指数,指数通过2的指数幂缩放尾数
Imaginary literals 虚数后缀i可以与任何(二进制、十进制、十六进制)整数或浮点字面值一起使用
Digit separators 可以使用下划线分隔(分组)任何数字,例如:1_000_000、0b_1010_0110、3.1415_9265,下划线可能出现在任何两位数字或字符前缀和第一位数字之间
Go 1.13之前为满足左移位(<<)和右移位(>>)运算符的操作数必须是无符号数的限制,需要进行大量手动uint类型转换。根据有符号移位计数提议,Go 1.13移除了移位操作数必须是无符号数的限制,消除手动类型转换的需要
语言层面的改变通过修改编译器以及 go/scanner、text/scanner (number literals)、go/types (signed shift counts)库来实现
如果代码使用modules和go.mod文件指定语言版本,要使用语法新特性需确保将其版本至少设置为1.13。可以直接编辑go.mod文件或使用命令`go mod edit -go=1.13`
工具链
Modules
环境变量
GO111MODULE 依然以auto为默认值,但是只要当前目录包含或者其子目录包含go.mod文件--即使当前目录在GOPATH/src中,都会激活go命令的module-aware模式。这项更改简化来GOPATH/src中现有代码的迁移并且继续维护module-aware和non-module-aware模式
GOPRIVATE 这个新的环境变量指示非公开的module路径,它用在较低级别的GONOPROXY和GONOSUMDB变量的默认值,通过代理提取哪些模块并使用校验和数据库进行验证,从而提供更细粒度的控制
GOPROXY environment variable 可以设置为以逗号分隔的代理URL列表或特殊token direct,默认值https://proxy.golang.org,direct。当解析包含其模块的包路径时,go命令将在列表中的每一个代理上陆续尝试所有候选模块路径。代理不可达或HTTP状态码不是400或410,将终止搜索而无需咨询其余代理
GOSUMDB 标识数据库名称以及可选的公钥和服务器URL,以查询主模块的go.sum文件中尚未列出的模块和校验和。如果GOSUMDB不包括显示的URL,通过探测GOPROXY URLs选择支持校验和数据库的endpoint作为URL,如果任何代理都不支持则返回到指定数据库的直接连接。如果GOSUMDB设置为off,则不会查询校验和数据库只验证go.sum文件中的现有校验和
无法访问默认代理和校验和数据库的用户(防火墙)可能会通过将GOPROXY设置为直接和/或将GOSUMDB设置为关闭来禁用
go env -w 可以设置用户的环境变量,与平台无关。默认的设置存储在go/env os.UserConfigDir()文件内
go env -w GOPROXY=direct
go env -w GOSUMDB=off
go env -u # (unset)取消设置
go get
在module-aware模式下,go get搭配-u参数现在只更新一个更小的模块集合,这与GOPATH模式下使用go get -u
命令更新软件包集更加一致
go get -u <package name>继续更新命令行上命名的模块和包,但额外只更新命名包导入的包的模块; go get 子命令现在支持版本后缀@patch,@patch后缀表示指定的模块或包含命名包的模块应更新为具有与构建列表中找到的版本相同的主要和次要版本的最高修补程序版本
特别注意,go get -u(不带参数)现在只更新当前目录中包的传递导入。要更新主模块传递的所有包(包括测试依赖项),请使用go get -u all
。不再支持go get -m
(go在加载包之前停止)子命令; go get -d
(下载构建命名包的依赖关系所需的源代码之后停止)子命令仍然受支持
go get -u
只更新非测试依赖,与GOPATH模式一致;它现在同样接受-t标识,导致go get包含由命令行上命令的包测试包导入
Version validation
从版本控制系统中提取模块时,go命令现在对请求的版本字符串执行附加验证--go命令验证伪版本和版本控制元素之间的映射
版本前缀必须vX.0.0的形式,或者从修订版本的祖先上的标记派生,或者从包含指定修订本身的构建元数据标记派生
日前字符串必须与修订的UTC时间戳匹配
修订版的短名称必须使用与go命令生成的字符数相同的字符数(对于git使用的SHA-1哈希对应一个12位数的前缀)
如果主模块中的require指令使用无效的伪版本,通常可以通过将版本编辑为提交hash并重新运行go命令来纠正,例如:go list -m all 或 go mod tidy
example
require github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c
(redacted to) => require github.com/docker/docker e7b5f7dbe98c
(currently resolves to) =>require github.com/docker/docker v0.7.3-0.20190319215453-e7b5f7dbe98c
Compiler Toolchain
编译器有一个新的更精确的逃逸分析实现。对大多数代码应该是一个改进(更多的Go变量和表达式分配在栈而不是堆);但是这种提高的精度也可能会破坏之前运行的代码使之变得无效(例如,违反unsafe.Pointer安全规则的代码)
Assembler
汇编器现在支持许多ARM v8.1中引入的许多原子指令
运行时
Out of range panic 消息现在包含出界的索引和切片的容量/长度,例如:切片s[3]长度为1,Panic消息表示runtime error: index out of range [3] with length 1
此版本将大多数使用defer的性能提高了30%
运行时更积极地将内存还给操作系统,以使其可供共同租户应用程序使用
核心库
TLS 1.3
Go 1.13的crypto/tls包默认支持TLS(可以将tls13=0添加到GODEBUG环境变量来禁用)
crypto/ed25519 实现Ed25519签名,这个功能之前由 golang.org/x/crypto/ed25519 包提供,与go 1.13+一起使用时它成为 crypto/ed25519 的包装器
Error wrapping
错误e可以通过提供返回w的Unwrap方法来包装另一个错误w。e和w都可用于程序,允许e为w提供额外的上下文或重新解释它,同时仍然允许程序基于w做出决策。更多细节清阅读errors package documentation或Error Value FAQ
更新的库
库的微小更改和更新,会考虑与Go 1的兼容性
bytes 新的ToValidUTF8函数返回给定字节切片的副本,每次运行的无效UTF-8字节序列由给定切片替换
context 通过WithValue返回的上下文格式不再依赖于fmt,也会以相同的方式进行字符换化。依赖于之前确切的字符串化的代码可能会受到影响
crypto/tls 现在已弃用对SSL 3.0版(SSLv3)的支持,将在go 1.14中删除,默认情况下禁用。TLS 1.2和1.3现在支持Ed25519证书
crypto/x509 根据RFC 8410以及ParsePKCS8PrivateKey, MarshalPKCS8PrivateKey, and ParsePKIXPublicKey函数,证书和证书请求现在支持Ed25519密钥。搜索系统根目录的路径现在包括 /etc/ssl/cert.pem
database/sql 新增 NullTime 表示time.Time为null; 新增NullInt32表示int32类型null
debug/dwarf 如果在graph类型中遇到未知DWARF标记Data.Type方法不再panic,相反,它表示具有UnsupportedType类型的对象
errors 新增三个函数
**As** 函数查找给定错误链(包装错误序列)中与给定目标类型匹配的第一个错误,如果找到则将目标设置为error value
**Is** 该函数报告给定的错误值是否与另一个链中的错误匹配
**Unwrap** 返回在给定错误(如果存在)上调用Unwrap的结果
fmt
%O以基数8格式化整数,省略0o前缀
scanner现在可接收十六进制浮点数值、下划线分隔数字、ob和0o前缀
Errorf函数有一个新的动词%w,其操作数必须是一个错误。从Errorf返回的错误将有一个Unwrap方法,它返回%w的操作数
go/scanner scanner 已经被更新到能识别新的Go数字文字,特别是具有0b/0B前缀的二进制文字、具有0o/0O前缀的八进制文字和具有十六进制尾数的浮点数,虚数后缀i可以与任何数字文字一起使用、下划线可以用作数字分隔符进行分组
go/types type-checker已经被更新为遵循整数移位新规则
html/template 使用<script>标记并将"module"设置为type属性时,代码将被解释为JavaScript模式脚本
log 新的Writer函数返回标准logger的输出目标
math/big
对于Float.Parse和Int.SetString如果基数是0,为方便阅读可以在数字之间使用下划线
Rat.SetString接受非十进制浮点表示
math/bits Add、Sub、Mul、RotateLeft和ReverseBytes 执行时间保证独立于输入
net 在Unix系统上use-vc被设置在resolv.conf,TCP用于DNS解析
新的字段ListenConfig.KeepAlive指定侦听器接受的网络连接保持活动的时段。默认值为0,启用TCP keep-alive,设置为负值可以禁用此功能
net/http
新字段Transport.WriteBufferSize 和 Transport.ReadBufferSize 允许指定传输读/写缓冲区的大小。如果任意字段为0,则使用默认大小4KB
新字段 Transport.ForceAttemptHTTP2 当提供了非零Dial、DialTLS或DialContext函数或TLSClientConfig,它控制是否启用HTTP/2
Transport.MaxConnsPerHost 在HTTP/2可以正常使用
TimeoutHandler's ResponseWriter 现在实现Pusher和Flusher接口
新增103状态码,表示Early Hints
Transport 现在使用 Request.Body's io.ReaderFrom 实现(如果可用) 来优化写入正文
os、os/exec、reflect、runtime、strconv、strings、sync、syscall、syscall/js、testing、text/scanner、text/template、time、unicode
这些包也有些许更新,这里不一一列出
小结
本文抛砖引玉式地对Go1.13的新特性做了简单介绍,更多特性需要在实际应用中去深入挖掘