VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > 简明python教程 >
  • Go Modules 终极入门(2)

func main() { fmt.Println(mquote.GetHello())}

然后在项目根目录执行 go get github.com/eddycjy/mquote 命令,如下:

  •  
  •  
  •  
  •  
$ go get github.com/eddycjy/mquote go: finding github.com/eddycjy/mquote latestgo: downloading github.com/eddycjy/mquote v0.0.0-20200220041913-e066a990ce6fgo: extracting github.com/eddycjy/mquote v0.0.0-20200220041913-e066a990ce6f

查看 go.mod 文件

在初始化项目时,会生成一个 go.mod 文件,是启用了 Go modules 项目所必须的最重要的标识,同时也是 GO111MODULE 值为 auto 时的识别标识,它描述了当前项目(也就是当前模块)的元信息,每一行都以一个动词开头。

在我们刚刚进行了初始化和简单拉取后,我们再次查看 go.mod 文件,基本内容如下:

  •  
  •  
  •  
  •  
  •  
  •  
  •  
module github.com/eddycjy/module-repo
go 1.13
require (	github.com/eddycjy/mquote v0.0.0-20200220041913-e066a990ce6f)

为了更进一步的讲解,我们模拟引用如下:

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
module github.com/eddycjy/module-repo
go 1.13
require (    example.com/apple v0.1.2    example.com/banana v1.2.3    example.com/banana/v2 v2.3.4    example.com/pear // indirect    example.com/strawberry // incompatible)
exclude example.com/banana v1.2.4replace example.com/apple v0.1.2 => example.com/fried v0.1.0 replace example.com/banana => example.com/fish
  • module:用于定义当前项目的模块路径。
  • go:用于标识当前模块的 Go 语言版本,值为初始化模块时的版本,目前来看还只是个标识作用。
  • require:用于设置一个特定的模块版本。
  • exclude:用于从使用中排除一个特定的模块版本。
  • replace:用于将一个模块版本替换为另外一个模块版本。

另外你会发现 example.com/pear 的后面会有一个 indirect 标识,indirect 标识表示该模块为间接依赖,也就是在当前应用程序中的 import 语句中,并没有发现这个模块的明确引用,有可能是你先手动 go get 拉取下来的,也有可能是你所依赖的模块所依赖的,情况有好几种。

查看 go.sum 文件

在第一次拉取模块依赖后,会发现多出了一个 go.sum 文件,其详细罗列了当前项目直接或间接依赖的所有模块版本,并写明了那些模块版本的 SHA-256 哈希值以备 Go 在今后的操作中保证项目所依赖的那些模块版本不会被篡改。

  •  
  •  
  •  
  •  
  •  
github.com/eddycjy/mquote v0.0.1 h1:4QHXKo7J8a6J/k8UA6CiHhswJQs0sm2foAQQUq8GFHM=github.com/eddycjy/mquote v0.0.1/go.mod h1:ZtlkDs7Mriynl7wsDQ4cU23okEtVYqHwl7F1eDh4qPg=github.com/eddycjy/mquote/module/tour v0.0.1 h1:cc+pgV0LnR8Fhou0zNHughT7IbSnLvfUZ+X3fvshrv8=github.com/eddycjy/mquote/module/tour v0.0.1/go.mod h1:8uL1FOiQJZ4/1hzqQ5mv4Sm7nJcwYu41F3nZmkiWx5I=...

我们可以看到一个模块路径可能有如下两种:

  •  
  •  
github.com/eddycjy/mquote v0.0.1 h1:4QHXKo7J8a6J/k8UA6CiHhswJQs0sm2foAQQUq8GFHM=github.com/eddycjy/mquote v0.0.1/go.mod h1:ZtlkDs7Mriynl7wsDQ4cU23okEtVYqHwl7F1eDh4qPg=

h1 hash 是 Go modules 将目标模块版本的 zip 文件开包后,针对所有包内文件依次进行 hash,然后再把它们的 hash 结果按照固定格式和算法组成总的 hash 值。

而 h1 hash 和 go.mod hash 两者,要不就是同时存在,要不就是只存在 go.mod hash。那什么情况下会不存在 h1 hash 呢,就是当 Go 认为肯定用不到某个模块版本的时候就会省略它的 h1 hash,就会出现不存在 h1 hash,只存在 go.mod hash 的情况。

查看全局缓存

我们刚刚成功的将 github.com/eddycjy/mquote 模块拉取了下来,其拉取的结果缓存在  $GOPATH/pkg/mod和 $GOPATH/pkg/sumdb 目录下,而在mod目录下会以 github.com/foo/bar 的格式进行存放,如下:

  •  
  •  
  •  
  •  
  •  
  •  
  •  
mod├── cache├── github.com├── golang.org├── google.golang.org├── gopkg.in...

需要注意的是同一个模块版本的数据只缓存一份,所有其它模块共享使用。如果你希望清理所有已缓存的模块版本数据,可以执行 go clean -modcache 命令。

Go Modules 下的 go get 行为

在拉取项目依赖时,你会发现拉取的过程总共分为了三大步,分别是 finding(发现)、downloading(下载)以及 extracting(提取), 并且在拉取信息上一共分为了三段内容:

image

需要注意的是,所拉取版本的 commit 时间是以UTC时区为准,而并非本地时区,同时我们会发现我们 go get 命令所拉取到的版本是 v0.0.0,这是因为我们是直接执行 go get -u 获取的,并没有指定任何的版本信息,由 Go modules 自行按照内部规则进行选择。

go get 的拉取行为

刚刚我们用 go get 命令拉取了新的依赖,那么 go get 又提供了哪些功能呢,常用的拉取命令如下:

命令 作用
go get 拉取依赖,会进行指定性拉取(更新),并不会更新所依赖的其它模块。
go get -u 更新现有的依赖,会强制更新它所依赖的其它全部模块,不包括自身。
go get -u -t ./... 更新所有直接依赖和间接依赖的模块版本,包括单元测试中用到的。

那么我想选择具体版本应当如何执行呢,如下:

命令 作用
go get golang.org/x/text@latest 拉取最新的版本,若存在tag,则优先使用。
go get golang.org/x/text@master 拉取 master 分支的最新 commit。
go get golang.org/x/text@v0.3.2 拉取 tag 为 v0.3.2 的 commit。
go get golang.org/x/text@342b2e 拉取 hash 为 342b231 的 commit,最终会被转换为 v0.3.2。

go get 的版本选择

我们回顾一下我们拉取的 go get github.com/eddycjy/mquote,其结果是 v0.0.0-20200220041913-e066a990ce6f,对照着上面所提到的 go get 行为来看,你可能还会有一些疑惑,那就是在 go get 没有指定任何版本的情况下,它的版本选择规则是怎么样的,也就是为什么 go get 拉取的是 v0.0.0,它什么时候会拉取正常带版本号的 tags 呢。实际上这需要区分两种情况,如下:

  1. 所拉取的模块有发布 tags:
    • 如果只有单个模块,那么就取主版本号最大的那个tag。
    • 如果有多个模块,则推算相应的模块路径,取主版本号最大的那个tag(子模块的tag的模块路径会有前缀要求)
  2. 所拉取的模块没有发布过 tags:
    • 默认取主分支最新一次 commit 的 commithash。

没有发布过 tags

那么为什么会拉取的是 v0.0.0 呢,是因为 github.com/eddycjy/mquote 没有发布任何的tag,如下:


相关教程