理解Go Modules
文章目录
【注意】最后更新于 February 27, 2021,文中内容可能已过时,请谨慎使用。
Go Modules是Go 1.11引入的,为了解决Go项目的依赖问题。从go 1.16开始,go modules开始成为Go默认的包依赖管理工具。
go moudle是一组go package的集合
一个Go Module实际上是由一组Go的Package的集合。 构建Go Module的过程需要先确定依赖的其他Go Module的版本、编译包、将编译的目标文件链接到一起。
一个Go项目就是使用go mod
创建的一个Go Module,由多个Go package组成,这个项目被保存在一个代码库中(如git)。
也就是说这个代码库中有多个go的package,如https://github.com/grpc/grpc-go这个项目。
每个Go Module根目录中会有一个go.mod文件描述module的元数据信息。
看一下grpc-go
这个项目的目录结构:
|
|
可以看到grpc-go
这个go module就是由一组go pacakge组成,在根目录里有一个go.mod
文件,内容如下:
|
|
go.mod
文件的第1行声明了go moudle的路径(path)。grpc-go
这个module的path是google.golang.org/grpc
。 moudle path有点其他语言中的命名空间的意思,当需要导入go module中的某个包时,需要以module-path/包子目录名称
,例如:import "google.golang.org/grpc/codes"
导入了google.golang.org/grpc
这个go module的codes
包。go.mod
文件第3行的go 1.14
用于指明Go的版本,用来说明go.mod
文件是使用哪个Go版本中go module语义编写的。因为go mod
被直接集成为go的子命令。require
块中的内容用来配置go module依赖了哪些外部的go module。
go module基于语义化版本
go moudle基于语义化版本,采用v<major>.<minor>.<patch>
的格式,例如grpc-go依赖的github.com/google/uuid
这个go moudle的版本是v1.1.2
。
语义版号的递增规则如下:
- major(主版本号): 当做了不兼容的API修改时,一般是重大架构、技术、功能升级,API已经不兼容原来的版本
- minor(次版本): 当做了向下兼容的功能性新新增,一般是正常的版本、功能迭代,要求API向后兼容
- patch(修订版本号):当做了向下兼容的问题修正,要求API向后兼容
在语义化版本的规范下,使用github.com/google/uuid
这个外部依赖的话,grpc-go选择任何v1.x.y
都是兼容现在的代码的,例如后续的v1.1.3
, v1.2.0
。
如果有一天github.com/google/uuid
发布了v2.0.0
的版本,grpc-go直接修改了go.mod
升级了依赖的版本到v2.0.0
,如果按照前面的go module依赖导入规则,就会出现编译错误,因为主版本号升级后不承诺API的兼容性。
针对这个问题Go Module给的解决方案是,从主版本号的2
开始将主版本号加入到go moudle的path中,具体规则如下:
语义化版本 | module path | 导入go moudle中的包 |
---|---|---|
v0.x.y | github.com/google/uuid | import “github.com/google/uuid” |
v1.x.y | github.com/google/uuid | import “github.com/google/uuid” |
v2.x.y | github.com/google/uuid/v2 | import “github.com/google/uuid/v2” |
v3.x.y | github.com/google/uuid/v3 | import “github.com/google/uuid/v3” |
这样如果将项目依赖的外部go moudle的主版本号升级时,就需要切换moudle path和代码中导入package路径,同时对使用的不兼容的API做出修改调整。
关于传递依赖如何选择,例如我们正在开发的A moudle同时依赖了B module和C moudle,而B依赖v1.1.0的D,C依赖v1.2.0的D,D的最新版本是v1.3.0。 使用go mod时,项目A通过传递依赖使用的C的版本将会是v1.2.0。因为按照语义化版本,主版本号相同的话,次版本号越大的其稳定性和安全性应该是更好的,由于B和C传递的版本中选择了次版本号更大的版本。
命令
go modules直接作为子命令集成在go中:
|
|
参考
文章作者 青蛙小白
上次更新 2021-02-27