查看原文
其他

Go1.21 速览:go.mod 的 Go 版本号将会约束 Go 程序构建,要特别注意了!

陈煎鱼 脑子进煎鱼了 2024-05-03

大家好,我是煎鱼。

之前 Go 核心团队的负责人 Russ Cox 针对 Go 的向前兼容(指的是旧版本的 Go 编译新的 Go 代码),进行了进一步的设计。

重点内容如下:

  1. 新增 GOTOOLCHAIN 环境变量的设置。
  2. 改变在工作模块(work module)中解释 go 行的方式,增加了新的工具链(toolchain)行以此实现声明。此对应的是 go.mod 文件的 go 行和 toolchain 行。
  3. 对 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 新版本的最新资讯和特性分享,欢迎持续关注我。

推荐阅读


关注和加煎鱼微信,

一手消息和知识,拉你进技术交流群👇



你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!

继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存