logo头像

Aoho's Blog

Go 1.13 正式发布

本文于2107天之前发表,文中内容可能已经过时。

Go 1.13

Go 1.12 在今年 2 月份对外发布。相较于之前增加了 go modules 机制、WebAssembly 支持的 Go 1.11,变化略小。

就在这周,最新 Go 版本 1.13 在 Go 1.12 发布六个月后推出,它的大部分变化在于工具链、运行时和库的实现,该版本保存与 Go 1 的兼容性承诺。从 Go 1.13 开始,Go 命令默认使用 Go module mirror 和 Go checksum database 来下载和认证 modules。

重大改进如下:

  • 数字文法的改进
  • 错误封装改进
  • 默认启用 TLS 1.3
  • 提升对 Module 的支持
  • 性能提升

1. 数字文法的改进

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 移除了移位操作数必须是无符号数的限制,消除手动类型转换的需要

1
2
3
4
var i int = 5

fmt.Println(2 << uint(i)) // before go 1.13
fmt.Println(2 << i) // in go 1.13 and later version

不过值得注意的是:go 1.12版本在go.mod文件中增加了一个go version的指示字段,用于指示该module内源码所使用的 go版本。Go 1.13的发布文档强调了只有在go.mod中的go version指示字段为go 1.13(以及以后版本)时,上述的语言特性变更才会生效。

2. 提升对 Module 的支持

Go核心团队也针对这些反馈对Go module机制进行了持续地优化。在Go 1.13中,Go module的一些改变如下。

2.1 Modules 环境变量

1
export GOPROXY=https://goproxy.cn,direct

国内可使用如上的配置。

  • GOSUMDB, 标识数据库名称以及可选的公钥和服务器URL,以查询主模块的go.sum文件中尚未列出的模块和校验和。如果GOSUMDB不包括显示的URL,通过探测GOPROXY URLs选择支持校验和数据库的endpoint作为URL,如果任何代理都不支持则返回到指定数据库的直接连接。如果GOSUMDB设置为off,则不会查询校验和数据库只验证go.sum文件中的现有校验和无法访问默认代理和校验和数据库的用户(防火墙)可能会通过将GOPROXY设置为直接和/或将GOSUMDB设置为关闭来禁用。
1
go env -w GOSUMDB=off

GOSUMDB关闭后,仅能使用本地的go.sum进行包的校验和校验了。

2.2 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包含由命令行上命令的包测试包导入。

2.3 版本校验

从版本控制系统中提取模块时,go命令现在对请求的版本字符串执行附加验证–go命令验证伪版本和版本控制元素之间的映射。

版本前缀必须vX.0.0的形式,或者从修订版本的祖先上的标记派生,或者从包含指定修订本身的构建元数据标记派生。

日期字符串必须与修订的UTC时间戳匹配。

修订版的短名称必须使用与go命令生成的字符数相同的字符数(对于git使用的SHA-1哈希对应一个12位数的前缀)。

如果主模块中的require指令使用无效的伪版本,通常可以通过将版本编辑为提交hash并重新运行go命令来纠正,例如:go list -m allgo mod tidy

3. Go 错误处理

Go核心团队早在一年前就提出了关于go错误处理的多个proposal,其中涉及解决if err != nil 大量重复问题的,有解决错误包装(wrap)问题的,errors 新增三个函数,有解决error value比较问题的。

  • 通过标准库增加了errors.Is和As函数来解决error value比较问题
  • 增加errors.Unwrap来解决error unwrap问题。

并且Go通过在fmt.Errorf中新增的”%w”动词来协助Gopher快速创建一个包装错误,创建的error变量实现了下面接口:

1
2
3
4
interface { // 匿名接口

Unwrap() error
}

4. 默认启用 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 的包装器。

5. 性能提升

Go 1.13中能带来运行时的变动主要有三个:

  • Out of range panic 消息现在包含出界的索引和切片的容量/长度,例如:切片s[3]长度为1,Panic消息表示runtime error: index out of range [3] with length 1
  • 此版本将大多数使用defer的性能提高了30%
  • 优化后的逃逸分析(escape analysis)让编译器在选择究竟将变量分配在stack上还是heap上的时候更加精确。在老版本里分配到heap上的变量,在Go 1.13中可能就会分配到stack上,从而减少内存分配的次数,一定程度上减轻gc的压力,达到性能提升的目的。

小结

Go 2 是这两年 Go 项目的核心主题。Go 项目组也一直在摸索着向 Go 2 演化的节奏和过程规范,并已经从 Go 1.11 版本起做出了实质性的动作:添加 go module 机制、错误处理优化、泛型讨论和多次草案的发布等。

Go 1.13版本的发布标志着Go向着Go2的目标又迈出了坚实的一步。

关于 Go 1.13 的详细发布日志,可参见 https://golang.org/doc/go1.13。

订阅最新文章,欢迎关注我的公众号

微信公众号

微信打赏

赞赏是不耍流氓的鼓励

评论系统未开启,无法评论!