golang 1.13

Go SDK 1.13之前,很多可以安全地开辟在栈上的内存因为编译器中的逃逸分析器不够智能的原因而被开辟在了堆上。这在一定程度上影响了程序执行效率。从Go SDK 1.13开始,标准编译器将采用一个新的逃逸分析器,从而将避免很了多不必要的在堆上开辟内存的情况。

Go SDK 1.13之前,所有的defer延迟调用都是记录在堆上的,这严重影响了defer延迟调用的执行效率。从Go SDK 1.13开始,满足某些条件的某些defer延迟调用(标准库中93%的延迟调用满足此条件)将被记录在栈上而不是堆上,从而提高了defer延迟调用的执行效率。



官方Go runtime 1.13将对sync.Pool中的对象回收时机策略做出调整。在1.12版本及以前的版本中,在每轮垃圾回收过程中,每个sync.Pool实例中的所有缓存对象都将被无条件回收掉。从1.13版本开始,如果一个sync.Pool实例在上一轮垃圾回收过程结束之后仍然被使用过,则其中的缓存对象将不会被回收掉。此举对于使用sync.Pool来提升效率的程序来说,将大大减少周期性的因为缓存被清除而造成的瞬时效率下降。



从Go SDK 1.13开始,编译输出的二进制可执行文件中将包含所用Go编译器的版本和此执行文件所依赖的各种第三方库包的版本号。我们可以使用命令go version binaryfile来查看一个二进制可执行文件是使用哪个版本的编译器编译的,或者使用命令go version -m binaryfile来查看包含在一个二进制可执行文件中的各个第三方依赖库包的版本号。



经过Go 1.11和Go 1.12近一年时间的磨合,Go modules版本依赖管理特性将从Go SDK 1.13开始大规模推荐使用。GOPATH环境变量的地位将减弱甚至丧失。GOBIN环境变量的地位将提升,因为go install命令仍需要一个路径来存储生成的二进制可执行文件。另外,伴随Go modules而生的GOPROXY环境变量的设置格式得到了增强。我们可以使用下面的格式来指定多个代理:



GOPROXY=proxy1,proxy2,proxy3
go命令在需要下载库包的时候将逐个试用设置中的各个代理,直到发现一个可用的为止。特别地,direct表示直连。一个设置例子:



GOPROXY=direct,https://proxy.golang.org,https://myproxy.mysite:8888
GOPROXY环境变量可以帮助我们下载墙外的第三方库包。当然,通过设置https_proxy环境变量设也可以达到此目的。但是一个公司通过在内部架设一个自己的goproxy服务器来缓存第三方库包,库包下载速度可能会更快。



为了防止出现node.js社区中大量的在使用npm时造成的不经意间引入木马库包的情况,Go官方推出了Go checksum database(sumdb):https://sum.golang.org。go命令将在必要的时候连接此服务来检查下载的第三方依赖包的哈希是否和sumdb的记录相匹配。有些遗憾,和proxy.golang.org类似,sum.golang.org也被墙了。但是我们同样可以设置https_proxy代理或者架设自己的sumdb服务器来解决这个问题。GOSUMDB环境变量用来设置第三方sum database服务器地址,其默认值为https://sum.golang.org。我们可以将其值设为off来关闭哈希检查,go命令的选项-insecure发挥同样的作用。当然,为了安全起见,一般情况下最好不要关闭哈希检查。



在设置了GOPROXY环境变量的情况下,我们可以设置GONOPROXY环境变量来设置不需要通过goproxy服务器来下载的库包。在设置了GOSUMDB环境变量的情况下,我们可以设置GONOSUMDB环境变量来设置不需要哈希检查的库包。



通过以上介绍,我们可以看到,go命令需要的环境变量增加了不少。为了管理这些环境变量,go env子命令添加了一个选项-w,用来设置全局go环境变量。比如,在Linux系统上,命令go env -w GOBIN=$HOME/bin用来设置GOBIN环境变量。




  1. 移位操作中的右操作数将允许为有符号整数
    截至目前,移位操作(«和»)中的右操作数必须为无符号类型确定整数或者可以表示成uint值的类型不确定值。从 Go 1.13 开始,移位操作中的右操作数将可以是任何整数类型(包括有符号类型)的类型确定值或者可以表示成任何整数类型的不确定值。但是如果一个右操作数是一个常量,则它仍旧必须为非负。



比如,下面这行在 Go 1.12-版本中编译不过,但是从 Go 1.13 开始,将编译没问题。



var _ = 1 « int(5)
注意,当一个非常量负整数被用作移位操作中的右操作数时,此操作将造成一个恐慌,比如下面这段代码:



var x = -2
var _ = 1 « x // panic!



  1. 更多的数值字面表示形式
    截至 Go 1.12 ,Go 只支持三种整数字面表示形式:十六进制形式、八进制形式和十进制形式。比如,下面是十进制数 15 的三种字面表示形式:



0xF // 十六进制表示(必须使用 0x 或者 0X 开头)
017 // 八进制表示(必须使用 0 开头)
15 // 十进制表示(必须不能用 0 开头)
Go 1.13 将引入二进制表示形式(千呼万唤始出来)。二进制形式必须使用0b或者0B开头,后面跟随的数字只能为0或1。一个示例:



0b11001 // 十进制的 25 的二进制字面表示
0B111 // 十进制的 7 的二进制字面表示
从 Go 1.13 开始,八进制数除了目前的使用 0 开头,将也可以使用0o或者0O开头。比如,下面三个八进制表示是等价的。



017 // 15 的八进制表示
0o17 // 15 的八进制表示
0O17 // 15 的八进制表示
另外,浮点数的字面表示形式也得到了扩充。可以在内存中精确表示的浮点数将可以用十六进制文字表示来表示。



和整数的十六进制文字表示一样,浮点数的十六进制文字表示也必须使用0x或者0X开头。
和整数的十六进制文字表示不同的是,字母p或者P可以出现在浮点数的十六进制文字表示中,其后跟随着一个幂指数。
另外要注意,e和E不能出现在浮点数的十六进制文字表示中。
一些浮点数的十六进制文字表示例子:



0x1p-2 // == 0.25
0x2.p10 // == 2048.0
0x1.Fp+0 // == 1.9375
0X.8p-0 // == 0.5
0X1FFFP-16 // == 0.1249847412109375
而下面这几个均不是合法的浮点数的十六进制文字表示。



0x.p1 // 浮点数的十六进制文字表示必须包含至少一个数字
1p-2 // p 指数形式只能出现在浮点数的十六进制文字表示中
0x1.5e-2 // e 和 E 不能出现在浮点数的十六进制文字表示中
下面这个表示是合法的,但是它不是浮点数的十六进制文字表示。事实上,它是一个减法算术表达式。其中的e为是十进制中的 14,0x15e为一个整数十六进制文字表示,-2并不是此整数十六进制文字表示的一部分。



0x15e-2 // == 0x15e - 2 (整数相减表达式)
数值字面表示形式的最后一点改动是:下划线_可以出现在数值字面表示形式中用做分段符以增强可读性。但是要注意,在一个数值字面表示中,一个下划线_不能出现在此字面表示的首尾,并且其两侧的字符必须为(相应进制的)数字字符或者进制表示头。



一些合法和不合法使用下划线的例子:



// 合法的使用下划线的例子
6_9 // == 69
0_33_77_22 // == 0337722
0x_Bad_Face // == 0xBadFace
0X_1F_FFP-16 // == 0X1FFFP-16



// 非法的使用下划线的例子
69 // 下划线不能出现在首尾
69
// 下划线不能出现在首尾
6_9 // 下划线不能相连
0_xBadFace // x 不是一个合法的八进制数字
1
.5 // .不是一个合法的十进制数字
1._5 // .不是一个合法的十进制数字



  1. 对 errors 标准库包的功能的增强
    除了上述语法变化,Go 1.13 中很可能将对 errors 标准库包的功能(当前只包含一个原型为func New(text string) error的函数)进行增强。由于篇幅原因,本文将不详述这些增强,本文在这里只是简单概括一下。对 errors 标准库包功能的增强本公众号将另开一篇文章详述。



简单说来,Go 1.13 主要将对errors标准库包做出如下增强:



支持 error 包裹嵌套(即支持 error 链)。
支持更好的 error 跟踪调试体验。
支持更完美的 error 格式打印。


Category golang