本月 17 日,Go 1.8 版本火热发布。相较于以往的版本,Go 1.8 具体有哪些新的特性呢?想必这是不少 Gopher 们热切关注和讨论的问题。作为著名的Golang 布道者,Gopher China 社区创始人,谢孟军早在今年一月的 ECUG Con 上就对 Golang 做出了历史版本的回顾和 1.8 版本的分析,本文就是对他的演讲实录。
谢孟军
Gopher China 社区创始人,著名开源框架 beego 开发者,畅销图书《Go Web 编程》作者,同时有 bat、bee 等开源软件。国内 Go 发展的主要推动者之一。
谢孟军:大家好,我是来自 Apple 的工程师,目前主要在从事工业自动化系统的架构和研发,今天很高兴来到这里跟大家分享一下关于 Go 的一些东西。Go 是 Google 的语言,Go 语言已经出来 6 年了,从 1.0 版本到 1.8 版本,今天最主要是跟大家分享一下 Go 在 1.8 版本中带来了哪些新特性。
Go 回顾
2012 年 3 月 Go 1.0 版本发布,这是一个标志性的事件。很多语言发布出来之后再次升级都会有或多或少不兼容的体验,但是 Go 官方团队在发布 1.0 的时候发布申明,后续的版本保证百分之百向前兼容,他们也遵守了当时的承诺。1.0、1.1、1.2、1.3 一直到 1.7,你的代码如果是 1.0 时候写的,现在升级到 1.7,都可以正常编译。其他语言里面我们可能都会有这样的体验,升级了一个新版本之后,需要花很多时间把代码兼容到新升级的版本中。所以对于一个语言来说,特性稳定是非常重要的。
Go 语言基本上保持了半年发布一个版本的节奏:
Go 1.8 版本带来了哪些新特性
语言层面
几乎没有任何改变,有一个小小的改进是:
struct 里面的字段都是一样的,但是 struct tag 一个是 foo,一个是 bar,新版本现在可以这样赋值了:V1=T1(V2)//now legal。
工具层面
首先是编译工具。大家知道,1.7 版本之后 Go 引入了 SSA,SSA 的引入把编译之后的二进制文件压缩小了,性能提升了。但是 1.7 版本中只针对了 64 位机器实现了 SSA,其他的全部还是用老的编译。但是在 1.8 版本中全部用 SSA 编译了,性能和大小基本上提升了 20% 到 30%。但是 Go 官方对所有的包测试下来,整体性能相对于 1.7 版本提升了将近 15% 。
go vet 大家写完代码之后可以用它检查一下是否符合标准,go vet 在 1.8 版本中增加了一些更加严格的方式:
-
copylocks for len&cap,当值传递到 len 函数的时候,锁拷贝进去之后很容易引起问题,这个时候,go vet 之前是检测不出来这个错误的,但是 1.8 版本可以检测出来这行代码是有问题的,存在锁拷贝。
-
JSON tags,在 1.7 版本之前写完全没有问题,在 1.8 版本中当两个 tag 一模一样时,会检测出两个 tag 之间应该用空格隔出来,而不是用“,”,这个地方必须空格。你的代码编译度没有任何问题,只是运行的时候存在一些问题。所以,go vet 是在你代码编译之前帮你检测代码层面存在的问题,相当于静态文件分析法。
-
Close before checking errors,当有错误的时候,那么 res 就会返回 nil ,这时候程序就崩溃了,1.8 版本的 vet 可以检测出来。 error 检测必须在调用 res 之前,这样的话就可以避免出现 panic 的情况。
Go 语言安装后之后需要设一个 GOPATH,但是在 Go 1.8 版本中实现了默认装后就会帮你设好一个 GOPATH 的环境变量。如果是在 Unix 环境下,就是在上图中 $HOME/go 那个目录下;如果是 Windows 环境下,就是在上图中 USERPROFILE 那个目录下。即目录已经帮你设好了,方便你装好 Go 就可以直接去用了。
在 Go 1.8 版本中支持动态加载 plugins,目前只支持 Linux 系统,Mac 和 Windows 都不支持。这里举个例子:首先我们定义一个函数,那么怎么把这个编译成插件呢?用一个参数 go build -buildmode=plugin,编译出 SO 文件,SO 文件编译完成之后怎么调用呢?在 1.8 里面增加了标准库的包 plugins,所以你可以使用 plugin.Open 动态地打开 SO 文件,就会返回 p,然后查找里面的函数,这个时候会返回一个符号,首先进行类型转换(类型断言),最后调用它,最后就可以调用 plugins 的东西了。plugin 的引入可以把使得 Go 的程序变成很小的一部分,Go 程序里面又分了微服务的感觉,采用模块化设计。但是这种问题又带来依赖的问题,目前我是持怀疑态度看待 plugin 的引入,但是对于部分企业来说是有用的,因为它可以做到中间件的部分自己去升级。但是我现在测试下来,这个 plugins,刚才 10 行不到的函数编译下来就有 5M 多,而且性能也是一个问题。
Go 里面新增加了一个命令叫 go bug,当你发现一个 bug,它会自动搜集系统的信息,打开浏览器,只要你填发现的问题就好了,非常方便你提 bug 的一个工具。
Go 在 1.8 版本中开始支持 tts 的调试。
runtime 层面
第一个是 argument liveness。在编写程序时,有些变量我们是希望它常驻内存的,在 1.7 的时候引入了一个函数 runtime.KeepAlive,这个变量保持在内存里面不要给 GC 干掉,它现在可以自己控制这个东西。1.8 版本针对它更加优化了一些。
第二个是 Concurrent Map Misuse。如果针对一个 Map 有并发的读和写是存在竞争的,1.6 版本之前不会把你的程序给崩溃掉,1.6 版本之后程序就会直接退出,这种情况怎么样避免呢?在编译的时候加 race,把代码竞争的情况全部检测出来。在 1.8 版本里面,针对这