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
或者语法的问题。