使用哪个版本的Go来编译依赖项?

huus2vyu  于 2023-05-20  发布在  Go
关注(0)|答案(2)|浏览(146)

无论何时编译Go程序,编译主代码和依赖代码时使用的是同一版本的Go吗?

idfiyjo8

idfiyjo81#

是的,依赖项是使用与代码相同的编译器编译的,因此它是相同的版本。
Go模块可以在其go.mod中声明minimum version directive,如下所示:

module example.com/mymodule

go 1.14

这以两种方式影响编译器行为:
如果依赖项go.mod中指定的版本比编译器的版本新,它将尝试编译,但如果遇到错误,则会输出一条消息,警告用户该模块已使用较新版本的Go编写。
如果依赖项go.mod中指定的版本比编译器的版本旧,则在指定版本之后引入的语言功能将被拒绝。

6yt4nkrj

6yt4nkrj2#

这是一个有趣的问题,并有一个微妙的答案。
对于老版本的Go,答案很简单:每个依赖项都是使用您在本地运行的Go版本编译的。如果你正在运行Go 1.9,并且你有为Go 1.10构建的依赖项,编译器将不会更明智,并尝试使用Go 1.9编译Go 1.10代码。只要在该依赖项中没有使用新特性,它就可以正常工作。同样,如果你有一个为Go 1.8构建的依赖项,它也会使用Go 1.9编译。
然而,对于现代版本的Go,以及任何使用go.mod文件的项目(或依赖项),行为是不同的。从Go Modules Reference中我们了解到:

  • 对于模块中的包,编译器拒绝使用在go指令指定的版本之后引入的语言功能。例如,如果一个模块有go 1.12指令,它的包可能不会使用像1_000_000这样的数字文字,这是在Go 1.13中引入的。

这意味着你的依赖项将只使用Go的 * 声明版本 * 中可用的功能。然而,它们仍然是使用现代Go运行时构建的。因此,在您的Go版本中发现的任何性能增强,安全改进等,都比依赖项的声明版本更新,仍然使用。
此外,同一文件的下一行说:

  • 如果一个较旧的Go版本构建模块的一个包并遇到编译错误,该错误会指出该模块是为较新的Go版本编写的。例如,假设一个模块使用go 1.13,而一个包使用数字文字1_000_000。如果该包是用Go 1.12构建的,编译器会注意到代码是为Go 1.13编写的。

所以这意味着如果你试图使用Go 1.19构建一个程序,并且其中一个依赖项声明了版本1.20 * 并且 * 存在编译错误,编译器输出将通知你潜在的兼容性问题。如果没有编译错误,您可能永远不会注意到差异(因为可能声明1.20的依赖项实际上并没有使用任何新的1.20编译器功能)。
这将产生比以前更明显的影响,可能在Go 1.22中,假设less error-prone loop variable scoping提案被接受并及时实现。因为这个建议将改变循环变量的处理方式,使其不向后兼容。假设Go 1.22中确实有这个,这意味着任何声明go 1.21或更早版本的模块都将使用旧的循环语义,而任何声明go 1.22或更高版本的模块都将使用新的循环语义。这将是Go语言第一次打破它的向后兼容性承诺,尽管有很好的理由(因为这个循环变量几乎每个人都被绊倒了)。

相关问题