介绍

  1. 在 Go1.8 时,GOPATH 已被弱化,开发者可以不显示的定义它,但它是依然客观存在的,Go会赋予它一个默认值(linux中默认为$HOME/go),在go的工具链依然有着至关重要的作用。
  2. 在 Go 1.11 时,Go引入了一种新的依赖管理 (“module-aware mode”),Go编译器将不再在GOPATH下面以及vendor下面搜索目标程序依赖的第三方Go packages。并且从 Go1.13 版本开始,该方式成为了Go语言默认的依赖管理工具:
    1. 某项目(通常是git的repo)的顶层目录下会放置一个 go.mod 文件,该文件定义了一个 module 。
    2. 该目录被称为 module root 目录。该目录以及其子目录下的所有 Go package 均归属于该 module(除了那些自身包含go.mod文件的子目录)。

准备工作 (环境变量)

  1. 升级 Go 版本 >= 1.11。
  2. 设置环境变量 GO111MODULE
    (Go版本>=1.13 可以不设置,因为默认使用go module。前提目录位于 $GOPATH/src之外)

GO111MODULE

GO111MODULE 可以设置为三个字符串值之一:

  • off:禁用 go module,编译时会从 GOPATH 和 vendor 文件夹中查找包。
  • on: 启用 go module,编译时会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod下载依赖。
  • auto:(默认)当项目在 GOPATH/src 目录之外,并且项目根目录有 go.mod 文件时,开启 go module。
    1. set GO111MODULE = on // win
    2. export GO111MODULE = on // mac
    如果不开启则后面命令将会提示:
    1. $ go mod init mytest
    2. go: modules disabled inside GOPATH/src by GO111MODULE=auto;
    3. see 'go help modules'

    go proxy

    Go语言在 1.13 版本之后 GOPROXY 默认值为 https://proxy.golang.org,在国内可能会存在下载慢或者无法访问的情况,所以十分建议大家将 GOPROXY 设置为国内:
    1. go env -w GOPROXY=https://goproxy.cn,direct // win
    2. export GOPROXY=https://goproxy.io // mac

运行上述命令在环境变量里设置后,不需要翻墙,也能快速的下载第三包了,简直感人!介绍两个国内的镜像点:


命令介绍

如果需要查看go module的详细文档(非常长),可以在控制台输入 go help modules,以下是go mod命令大全:

  1. download download modules to local cache (可以下载所需要的依赖,但是依赖并不是下载到$GOPATH中,而是$GOPATH/pkg/mod中,多个项目可以共享缓存的module)
  2. edit edit go.mod from tools or scripts (编辑go.mod文件)
  3. graph print module requirement graph (打印模块依赖图))
  4. init initialize new module in current directory (再当前文件夹下初始化一个新的module, 创建go.mod文件))
  5. tidy add missing and remove unused modules (增加丢失的module,去掉未用的module,并下载依赖)
  6. vendor make vendored copy of dependencies (将依赖复制到vendor下)
  7. verify verify dependencies have expected content (校验依赖)
  8. why explain why packages or modules are needed (解释为什么需要依赖)

示例

初始化

在 GOPATH 目录之外新建一个目录,并使用go mod init moduleName初始化生成 go.mod 文件:

  1. go mod init hello
  2. go: creating new go.mod: module hello

初始化生成的 go.mod 文件如下所示:

  1. module hello
  2. go 1.12

运行

新建一个 main.go 文件,写入以下代码:

  1. package main
  2. import "github.com/gin-gonic/gin"
  3. func main() {
  4. router := gin.Default()
  5. router.Run()
  6. }

运行 go run main.go 会发现 go mod 会自动下载依赖。

go.mod 文件:

  1. module testModule
  2. go 1.12
  3. require (
  4. github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect
  5. github.com/gin-gonic/gin v1.3.0 // indirect
  6. github.com/golang/protobuf v1.3.1 // indirect
  7. github.com/mattn/go-isatty v0.0.7 // indirect
  8. github.com/ugorji/go v1.1.4 // indirect
  9. gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
  10. gopkg.in/yaml.v2 v2.2.2 // indirect
  11. )

安装 package 的原则是先拉取最新的 release tag,若无 tag 则拉取最新的 commit。

还会自动生成一个 go.sum 文件来记录 dependency tree:

  1. github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
  2. github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
  3. ...

其他

go toolchain

go.mod 文件一旦创建后,它的内容将会被 go toolchain 全面掌控,go toolchain 会在各类命令执行时,比如go getgo buildgo mod等修改和维护 go.mod 文件。

mod

go.mod 提供了 module、exclude、require、replace 四个命令:

  • module 语句指定包的名字(路径);
  • exclude 语句可以忽略依赖项模块。
  • require 语句指定具体版本依赖项模块;
  • replace 语句可以替换依赖项模块;
    依赖库中的replace对你的主go.mod不起作用,比如github.com/smallnest/rpcxgo.mod已经增加了replace,但是你的go.mod虽然requirerpcx的库,但是没有设置replace的话, go get还是会访问golang.org/x

replace 使用

1. 替换无法直接获取的 package

由于某些已知的原因,并不是所有的 package 都能成功下载,比如:golang.org 下的包:

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

2. 一个项目引入本地另外一个项目

例1:rpc 开发时,client 调用另外一个服务的包。
例2:各工程调用公共组件

  1. go 1.13
  2. require github.com/go-gulu v0.0.0-incompatible
  3. replace github.com/go-gulu => /Users/yxs/GolandProjects/src/go-gulu
  1. go 1.12
  2. require go-gulu v0.0.0-incompatible
  3. replace go-gulu => /Users/yxs/GolandProjects/src/go-gulu
  1. 此处的 replace 稍微介绍下:
    1. 之所以要是 github.com/~ 的格式:
      1. go1.13 中, go module 名称规范要求路径的第一部分必须满足域名规范,否则可能汇报类似 malformed module path “article”: missing dot in first path element 这样的错误。
      2. go1.12 中,不会有报这个错误。建议的话,如果是公司内部使用,可以替换成公司内部域名。
    2. 第二个参数指定了不从远程获取,而是本地某个路径下的模块替换 github.com/~。

感谢

go module入门
Go学习总结-go module
golang包管理解决之道——go modules初探
Go 1.12中值得关注的几个变化