大家好,我是煎鱼。
之前 Go 核心团队的负责人 Russ Cox 针对 Go 的向前兼容(指的是旧版本的 Go 编译新的 Go 代码),进行了进一步的设计。
重点内容如下:
新增 GOTOOLCHAIN 环境变量的设置。
改变在工作模块(work module)中解释 go 行的方式,增加了新的工具链(toolchain)行以此实现声明。此对应的是 go.mod 文件的 go 行和 toolchain 行。
对 go get 等命令进行联动修改,允许对 GOTOOLCHAIN 和工作模块的 go 版本进行修改。
约束旧版本使用
从 Go1.21 开始,Go 语言将会将把 go.mod 文件中的 go 行解释为 Go 应用程序运行所需的最低 Go 版本。
像下面这个 Go 项目:
他在 go.mod 文件中的 go 行就是 Go1.13。只要你本地的 Go 版本大于等于 Go1.13 就可以编译成功。
反过来,失败的场景呢?例如:你的本地是 Go1.21 版本,在编译时遇到一个写着 Go1.22 的 go.mod 文件,那么编译器将拒绝构建该模块的代码。
结论上来讲,Go1.21 后,Go 应用程序就不能无视运行环境的 Go 版本任意的编译和启动了。需要符合 go.mod 文件中的 Go 行的版本要求,至少是等于或大于。
否则就可能会出现编译无法通过的情况。
增强构建约束
大家平时可以在 Go 源码文件顶部附近中看到一些神奇的 “符号”:
//go:build !windows && !plan9
又或是:
// +build !windows,!plan9
这是 Go 在构建时的构建约束。因为在真实环境中,可能需要为不同的编译环境编写不同的 Go 代码,所以需要做构建约束。
其主要支持如下几种:
指定编译的操作系统,例如:windows、linux 等,对应
runtime.GOOS
的值。指定编译的计算机架构,例如:amd64、386,对应
runtime.GOARCH
的值。指定使用的编译器,例如:gccgo、gc。
指定 Go 版本,例如:go1.9、go1.10 等。
指定自定义的标签,例如:编译时通过指定
-tags
传入的值。...
对于本次 go.mod 约束 Go 版本的行为,构建约束也进一步增强了规则,以此适配新的变化。
以前构建约束对于 Go 版本约束只能:
//go:build go1.9
现在可以:
//go:build go1.50 && !go1.60
还可以:
//go:build linux && go1.50 || darwin && go1.60
在 Go 最小版本的计算结果上,官方给出了几个案例,可以结合看看:
GoVersion(linux && go1.22)
结果:Go1.22。
// GoVersion((linux && go1.22) || (windows && go1.20))
结果:Go1.20(Windows)
// GoVersion(linux)
结果:空,也就是无 Go 版本约束
GoVersion((linux && !linux && go1.20) || go1.21)
结果:Go1.20
总结
在这次 Go1.21 的更新中,正式将多年前引入 go.mod 的 Go 行的版本声明使用了起来。想当年 Russ Cox 还是说这只是声明,暂时没有任何的作用。怕不是早已想好下一步了。
接下来 Go 将会有要求符合 go.mod 文件中的 Go 行的版本要求的基本构建要求,满足了才能成功运行起来。需要大家特别注意。
后面我还会继续更新 Go 新版本的最新资讯和特性分享,欢迎持续关注我。
推荐阅读
Go1.21 速览:新内置函数 clear、min、max 和新标准库包 cmp!
Go1.21 速览:过了一年半,slices、maps 泛型库终于要加入标准库。。。
Go1.21 速览:Go 终于打算进一步支持 WebAssembly 了。。。
关注和加煎鱼微信,
一手消息和知识,拉你进技术交流群👇
你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路。
日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!