gomoddownload使用场景(小白是这么理解Go)

Go Modules是Go 1.11引入的,为了解决Go项目的依赖问题。从go 1.16开始,go modules开始成为Go默认的包依赖管理工具。

gomoddownload使用场景(小白是这么理解Go)(1)

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 ├── Documentation ├── admin ├── attributes ├── authz ├── backoff ├── balancer ├── benchmark ├── binarylog ├── channelz ├── cmd ├── codes ├── connectivity ├── credentials ├── encoding ├── examples ├── grpclog ├── health ├── internal ├── interop ├── keepalive ├── metadata ├── peer ├── profiling ├── reflection ├── resolver ├── security ├── serviceconfig ├── stats ├── status ├── stress ├── tap ├── test ├── testdata ├── xds ... ... (省略了根目录里的一些go源码和其他的一些文件) ... ├── server.go ├── go.mod ├── go.sum └── xds

可以看到grpc-go这个go module就是由一组go pacakge组成,在根目录里有一个go.mod文件,内容如下:

module google.golang.org/grpc go 1.14 require ( github.com/cespare/xxhash/v2 v2.1.1 github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/protobuf v1.4.3 github.com/google/go-cmp v0.5.0 github.com/google/uuid v1.1.2 golang.org/x/net v0.0.0-20200822124328-c89045814202 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 google.golang.org/protobuf v1.25.0 )

  • 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传递的版本中选择了次版本号更大的版本。

参考
  • https://semver.org/lang/zh-CN/
,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页