Golang1.21兼容性问题-向前兼容
目录
向前兼容#
简单来说,就是老版本的编译器构建新的 go 版本写的代码。比如用 Go1.20的编译器构建 Go1.21的代码。
在 Go1.21之前,老版本的编译器是否可以构建新版本 Go 的代码,取决于 Go 模块的代码是否使用了新版本 Go 的语言特性。
- 例如,Go1.18才 release 的泛型特性,如果代码中使用了,那么 go1.17的编译器就无法编译。
但是当前代码中如果没有使用 go1.18的泛型特性,那么 go1.17的编译器编译出来的程序的行为就和 go1.18一样了吗?如果编译通过了,但是相同代码的结果却不一样,那么这就是向前兼容性的问题,而且更隐蔽,更难以发现。
- 例如,Go1.18默认移除了使用
[sha1-hash的x509证书的支持](https://tip.golang.org/doc/go1.18#sha1),虽然可以使用GODEBUG=x509sha1=1环境变量,保持默认行为和go1.18之前版本一致,但是默认行为其实是变更了。
为了提高向前兼容性,Go1.21现在会读取go.work或者go.mod的go line(注意不是toolchain line)严格限制编译器 Go 版本的最低要求:
Go line 就是
go关键字后面的版本号,比如在go.mod中是这样的
module github.com/meirongdev/go121expl
go 1.21.0 // 该行就是go line
本地工具链为 Go1.21之前版本#
如果当前本地安装的 Go 版本是1.20,那么不受上面限制的约束。就算你项目的依赖中的Go line为Go1.21,只要没有使用 Go1.21的新特性,那么构建很可能是可以成功的。但是GODEBUG的环境变量在两个版本之间控制的行为可能是不同的。还是有在运行时产生非预期结果的可能。
// go.mod
module github.com/meirongdev/go121expl/toolchain
go 1.20
require github.com/meirongdev/go121expl/toolchain/dep v0.1.1
replace github.com/meirongdev/go121expl/toolchain/dep => ./dep
本地工具链为 Go1.21之后版本,且大于或等于构建模块及其依赖的最高 go line 版本#
如果当前本地安装的 Go 版本是1.21.0或以上版本,当前项目的Go line为1.20,依赖了go line为1.21.0的模块,go build会提示
go: updates to go.mod needed; to update it:
go mod tidy
在go mod tidy执行后,main 模块的 go line会更新为1.21.0。
// go.mod
module github.com/meirongdev/go121expl/toolchain
go 1.21.0
require dep v0.1.1
replace dep => ./dep
如果当前工具链比所有模块的go line最高版本高,如 go1.21.3,那么会增加一个toolchain line,
// go.mod
module github.com/meirongdev/go121expl/toolchain
go 1.21.1
toolchain go1.21.3
require github.com/meirongdev/go121expl/toolchain/dep v0.1.1
replace github.com/meirongdev/go121expl/toolchain/dep => ./dep
本地工具链为 Go1.21之后版本,但小于所构建模块及其依赖的最高 go line 版本#
如果当前本地安装的 Go 版本是1.21.0或以上版本,当前项目的Go line为1.20,依赖了go line为1.21.1(及其以上版本的)的模块,会提示go: module ./dep requires go >= 1.21.1 (running go 1.21.0)。在go mod tidy执行之后,main 模块的go line会更新为1.21.1,但是会增加一个toolchain line为1.21.4。
$ go mod tidy
go: module ./dep requires go >= 1.21.1; switching to go1.21.4
// go.mod
module github.com/meirongdev/go121expl/toolchain
go 1.21.1
toolchain go1.21.4
require github.com/meirongdev/go121expl/toolchain/dep v0.1.1
replace github.com/meirongdev/go121expl/toolchain/dep => ./dep
为什么toolchain是go1.21.4而不是go1.21.1呢?这是[Go toolchain switches](https://go.dev/doc/toolchain)机制决定的。
1.21是目前 Go 最新的 release 版本,toolchain 会选择最新的的 patch 版本。
| 本地 Go 工具链版本 | main 模块 go line | dep 模块 go line | go build |
|---|---|---|---|
| 1.20 | 1.20 | 1.21.0 | 成功 |
| 1.21.0 | 1.20 | 1.21.0 | go: updates to go.mod needed; to update it: go mod tidy |
| 1.21.0 | 1.20 | 1.21.1 | go: module ./dep requires go >= 1.21.1 (running go 1.21.0) |
- Go1.21这种变动的好处是
- 这样让依赖于较新 Go 版本的修复的项目可以确保不会和老版本的 Go 工具链一起使用。
- 让使用新 Go 特性的项目给予更好地错误报告:当需要一个新的 go 版本时,该问题可以清楚地显示,而不是尝试构建代码,并打印各种关于
imports或者语法的问题。