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