一直以来,golang 官方都没有附带包管理工具,默认是通过 GOPATH 来管理第三方模块的,后来增加了 vendor 功能来隔离项目。 后面又出现了一些第三方的包管理工具,例如:godep、glide、govendor 等,都能很大程度上解决包管理的问题。

Go Modules 是什么

从2018年3月开始,官方就计划开始填坑了,见 https://github.com/golang/go/issues/24301。 在6,7月发布的beta版本中就已经正式装载了 Modules 功能,直到8月正式发布1.11版本,算是正式登上了历史舞台。

由于我8月正好新开始一个go项目,在调研包版本工具时发现了这个计划,并稍作尝试后,就决定使用这个了。 当然,刚开始的时候还是使用的beta版本,后面正式版本出来后,才切换为了正式版本。

按照官方的说法,Modules 能把关联的包都聚集在一起管理,能精确记录依赖要求,创建可重复的构建。

下面,我们来简要看看如何使用。

使用介绍

随意创建并进入一个目录:

mkdir -p ~/project/go_test/
cd ~/project/go_test/

初始化一个 module:

go mod init example.com/go_test

example.com/go_test 是要初始化的 module 名字。 这时会多出一个 go.mod 文件,如下:

module example.com/go_test

然后,写上一些代码:

$ cat <<EOF > hello.go
package main

import (
    "fmt"
    "rsc.io/quote"
)

func main() {
    fmt.Println(quote.Hello())
}
EOF

编译它:

go build

这时,查看 go.mod 文件:

module github.com/you/hello

require rsc.io/quote v1.5.2

它被增加了一行,描述了需要版本号为 v1.5.2rsc.io/quote 包。

同时,还新增了一个 go.sum 文件:

golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y=
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

它保存了每个包对应版本的加密校验和,用以验证所使用包的安全性。

是不是很简单!你无需关心 GOPATHvendor 的设置,它都会自动帮你处理好。

当然,你也可以手动管理包。

使用 go list -m all 可以查看当前已安装的包:

example.com/go_test
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0

直接使用 go get 命令来安装新包,例如:

go get github.com/golang/protobuf

查看 go.mod

module example.com/go_test

require (
    github.com/golang/protobuf v1.3.0 // indirect
    rsc.io/quote v1.5.2
)

对于项目中不再用到的包,可以使用 go mod tidy 命令来清除。 清除后,go.mod 文件又恢复之前的状态:

module example.com/go_test

require rsc.io/quote v1.5.2

还有一些其他的命令,可以通过 go mod 查看:

download    download modules to local cache
edit        edit go.mod from tools or scripts
graph       print module requirement graph
init        initialize new module in current directory
tidy        add missing and remove unused modules
vendor      make vendored copy of dependencies
verify      verify dependencies have expected content
why         explain why packages or modules are needed

解决的问题

对于一个包管理工具来说,有以下几个问题是着重需要解决的。 让我们来看看 Go Modules 是如何处理并解决的。

首先,也是最重要的一点就是要能知道安装了哪些包,以及对应的版本。 Go Modules 通过 go.mod 已经描述的非常清楚了。

其次,需要给每个项目一个独立的依赖环境。 Go Modules 通过引入 module 的概念,来给每个项目建立一个独立的环境。

再次,可以自动化选择所要依赖的版本。详细可以参考 https://github.com/golang/go/wiki/Modules#version-selection

最后,最好能避免相同的包在不同的项目中重复下载。 Go Modules 将所有的包在 $GOPATH/pkg/mod/ 中统一管理,这样就能避免重复下载了。

go1.11之前的版本

Go Modules 是1.11版本才装载的功能,但是官方也提供了之前的版本使用它的方法,那就是 vgo。 使用起来就是把所有操作命令中原本是 go 的地方换成 vgo 就可以了。

我稍微看了下这个项目的代码,它实际上就是把go1.11版本的 Modules 功能给封装了下,并提供一个 vgo 命令给开发者使用, 所以本质就是 Go Modules。

顺带一提,目前 GoLand 对这个功能支持的不够好,在命令行中能 import 的包,在 GoLand 中并不能正确的跳转到定义。 (后续补充:在经过了几次版本迭代之后,GoLand 已经能正确的处理 Modules 的功能了)。

总结

总体来说,我感觉官方的这个包管理工具还是很优秀的,使用起来很方便,并且也无需配置任何东西。 所以,非常值得大家一试。