还记得好多年前,我们才刚刚开始学习和使用 Go 这一门编程语言。当时依赖管理还在用 GOPATH 模式,为此大家基于此去开发和管理了很多配套工具和流程。随着 Go 模块管理(Module)的成熟,有在用新的,有在用旧的。GOPATH 的去留成为了一个折腾的问题。
GOPATH 存在的问题
现阶段 Go 维护既有的 GOPATH 模式,至少存在两个重要问题:
1.新特性更不上:在模块代理、校验和数据库等安全改进方面,旧的 GOPATH 模式已被抛在后面。Go 所有的迭代焦点都集中在模块管理(go.mod)上。
2.无法识别版本:旧的 GOPATH 模式的源代码布局,没有提供识别当前使用的 Go 语音版本的方法。
第一点还能说可以用,不跟进,似乎也没什么大问题。最烦的是第二点,之前在 GOPATH 和 Go Module 并立的年代。经常会遇到这个痛苦的坑。
这里 Go 程序读取模块会有一些分歧:
1.Module 模式的程序,读取 go.mod 的 go 行,确定版本为 Go 1.16。
2.GOPATH 模式的程序,由于无法得知版本,只能假设 Go 是最新版本。
这意味着,如果有人在 GOPATH 模式下开发了可下载的软件包,他们可以使用 Go 1.16 之后引入的语言特性,比如泛型。但当用户在 Module 模式下以模块的形式下载这些代码时,这些代码会被解释为 Go1.16,无法编译。随着时间的推移,其他语言特性或变更的出现,这种分歧会越来越大。
曾经的最后通牒
之前在 2021 年 2 月时,在 Go 官方博客上曾经对此作出公示,给出最后的通牒:
.可以通过将 GO111MODULE 环境变量设置为 off,仍然可以继续在 GOPATH 模式下构建包。
.我们计划在 Go1.17 中放弃对 GOPATH 模式的支持。
.Go1.17 将忽略 GO111MODULE 环境变量。如果有未在模块模式下构建的项目,现在是迁移的时候了。
从结果来看,现在 2024 年了,大家也知道了,Go1.17 及以后也没有放弃 GOPATH 模式。最后通牒是可以被打破的!
最终采取的策略和行动
1.承诺无限期保留 GO111MODULE=off 时,构建 GOPATH 布局源代码树的功能。
2.在 GOPATH 模式下完全禁用 go get,因为它能成功下载的代码越来越少,带来的开发体验也越来越差。
3.在 GOPATH 模式下,将把 Go 语言版本假设为 Go1.21,而不是继续假设为 “最新的 Go 版本”。这将确保如果在 Go 1.22 中更改 for 循环或在将来进行其他重大更改时,达到旧版代码也能继续编译的目的。
总结
这次针对 GOPATH 模式和 Module 模式的探讨和推进,仍然是由 Go 核心团队负责人 rsc 负责发起。最终的结论是 GOPATH 模式这种历史债务甩不掉,还是有人必须要使用的。但是我们也不能完全不管他。
答案是既要也要还要。所以对 GOPATH 模式和 Module 模式同时做了一些小处理,避免造成过大的冲突。最终结论是:无限期保留基本 GOPATH 模式的支持。此项变更在 Go1.22 时已经生效!