go模块的使用

monchickey

2019/08/08

go从1.11开始支持模块,也就是说源码不用再放在$GOPATH/src下面了,而可以在外面任意创建目录当做go的模块,这样比之前更灵活,而且这个可以配置依赖的版本以及支持版本的切换等,在以后的新版本中可能会取消src中编译的方式,而全部使用go mod的方式代替,使用go模块建议最低版本为1.12.x推荐使用最新版,从1.12.x之后默认支持go模块方式管理,不用再使用export GO111MODULE=on启用环境变量了,下面对go模块开发中基本的使用方法简单介绍下。

首先从一个空的模块开始,在$GOPATH之外的任意目录创建用于存放go模块的目录:

mkdir helloworld && cd helloworld/

然后开始初始化模块:

go mod init hello

这样就初始化了模块,名称为hello,同时在当前目录生成go.mod文件,内容默认有如下两行:

module hello
go 1.12

这个文件一旦存在之后,之后的所有操作都是基于模块的方式进行了,假设手动创建这个文件的话,不用执行go mod init hello也是一样的。

然后我们可以将代码放过来或者从头开发,过程中肯定会需要大量的第三方包,都需要下载,有很多包下载很慢或者得fq,那么可以先设置一下国内的代理,执行:export GOPROXY=https://goproxy.io 设置,通过这个网站代理下载模块速度比较快。设置之后需要执行:

go mod tidy

这个命令会自动收集代码中所有的依赖然后下载,并更新go.mod以及生成go.sum文件,go.sum这个文件包含更深层次的依赖关系,默认下载会下载包最新的tag或者commit,下载后go.mod内容示例可能如下:

module hello
go 1.12
require (
        github.com/OneOfOne/xxhash v1.2.5
        github.com/Shopify/sarama v1.22.1
        github.com/bitly/go-simplejson v0.5.0 // indirect
        github.com/bluele/gcache v0.0.0-20190518031135-bc40bd653833
        github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575
        github.com/go-redis/redis v6.15.2+incompatible
        github.com/json-iterator/go v1.1.6
        github.com/mozillazg/request v0.8.0
        github.com/satori/go.uuid v0.0.0-20181028125025-b2ce2384e17b
        gopkg.in/yaml.v2 v2.2.2
)

如果某个版本可能不是最适合的,可以修改后面的版本号,如果没有版本号只有某一次commit,可以直接将这个7位的commit放在后面,不用加v直接放commit即可,然后go会自动的找到这个commit并补全版本,补全后一般是v0.00-时间-commit这样。

现在可以执行编译:

go build

其实编译时也会自动下载所需的依赖,因此不执行上面的go mod tidy也是可以的,依赖也会自动下载,go模块的下载目录是在$GOPATH/pkg下面,而不会用到src目录,也就是说pkg下面都是第三方的包。

对于自己写的第三方模块,如果想用go模块的方式使用,第一种方法是上传到github等网站然后再下载,也可以使用replace语句指向本地的代码,比如:

require (
    github.com/aaaaa/bbbbb v0.0.0
)
replace github.com/aaaaa/bbbbb => /home/golang/src/github.com/aaaaa/bbbbb

这样go就不会去github找,而是直接使用本地的,后面的版本号也用不到,多个replace同样可以使用括号。

replace的另一种用法是将golang.org上面需要fq才能下载的包替换到github上,方便加速下载,一般golang.org上面的包在github上都有对应的仓库,这种使用replace语句也是可以的,这种替换前后都需要加版本号来定位,示例如下:

replace (
    golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a
)

实际项目中,如果使用git版本控制,go.mod和go.sum也要提交上去,因为这个关系到程序用到的具体版本。

引入当前模块下的包,比如当前模块是hello,引入当前模块下的a包则直接使用import "hello/a"即可,模块是最顶层的包,这和之前都放在src的调用方式类似。

reference:

go modules的官方文档:https://github.com/golang/go/wiki/Modules