Golang modules 初探

Posted GoCN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang modules 初探相关的知识,希望对你有一定的参考价值。

今天天色刚刚亮起,起床看到 golang 1.11 正式发版了,有着两个重要的特性:modules 和 WebAssembly。

本博文只要说的是 modules,congJava 转 golang 的同学肯定是对 golang 的包管理充满了无奈之情,我也曾在博客中介绍过 glide,也介绍过 dep,现在我们再一次升级介绍 modules。

什么是 modules

现在都在说 modules,那么它是什么? 
到文档看看 Modules, module versions, and more:

 
   
   
 
  1. A module is a collection of related Go packages. Modules are the unit of source code interchange and versioning. The go command has direct support for working with modules, including recording and resolving dependencies on other modules. Modules replace the old GOPATH-based approach to specifying which source files are used in a given build.

翻译一下:

 
   
   
 
  1. 模块是相关Go包的集合。modules是源代码交换和版本控制的单元。 go命令直接支持使用modules,包括记录和解析对其他模块的依赖性。modules替换旧的基于GOPATH的方法来指定在给定构建中使用哪些源文件。

可以得到两个重要信息:

  • Go 命令行支持 modules 操作

  • modules 用来替换 GOPATH 的

大家不需要太担心了,golang 1.11 版本仅仅是指对 modules 的初步支持,之前老的 GOPATH 还是可以继续使用的,有人说是在 golang 1.12 去除,但是我觉得有点早了,毕竟人的惯性不是这么容易改变的。

如何使用 modules

modules 是一个新的特性,那么就需要新的 Golang 版本进行支持了,可以到官网下载,一定要是 go 1.11 及以上的版本(写博文的时候 go 1.11 刚刚出来)。
这么部署就在这里说了,相信初学者也是知道怎么做的。

还有人记得 vendor 刚刚出来时候 golang 提供的环境变量 GO15VENDOREXPERIMENT吗?现在 modules 出来,按照惯例也提供了一个环境变量 GO111MODULE,这个变量的三个 1 太有魔性了。

GO111MODULE

GO111MODULE可以设置为三个字符串值之一:off,on 或 auto(默认值)。

  • off,则 go 命令从不使用新模块支持。它查找 vendor 目录和 GOPATH 以查找依赖关系; 也就是继续使用 “GOPATH 模式”。

  • on,则 go 命令需要使用模块,go 会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod 下载依赖。

  • auto 或未设置,则 go 命令根据当前目录启用或禁用模块支持。仅当当前目录位于 GOPATH/src 之外并且其本身包含 go.mod 文件或位于包含 go.mod 文件的目录下时,才启用模块支持。

Defining a module

开始的时候谁也不知道怎么使用?不过 go 已经给我提供了工具了,可以在控制台输入:

 
   
   
 
  1. go help modules

看到一大串的文档输出,看着都头疼了,一会儿我们再简要说明重点,现在先进行操作。

 
   
   
 
  1. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  2. $ export GO111MODULE=on  #开启modules

  3. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  4. $ go mod init  gitlab.luojilab.com/zeroteam/ddkafka # 创建go.mod

  5. go: creating new go.mod: module gitlab.luojilab.com/zeroteam/ddkafka

  6. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  7. $ ls    # 真的创建了,google大法好呀

  8. README.md  go.mod  models.go  mq_interface.go  sarama  segmentio

  9. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  10. $ cat go.mod    # 看看里面什么东西

  11. module gitlab.luojilab.com/zeroteam/ddkafka

  12. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  13. $ cd segmentio/

  14. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)

  15. $ go test   # 执行一下看看

  16. go: finding github.com/segmentio/kafka-go latest

  17. go: finding github.com/golang/glog latest

  18. go: downloading github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b

  19. go: downloading github.com/segmentio/kafka-go v0.0.0-20180716203113-48c37f796910

  20. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)

  21. $ go list -m

  22. gitlab.luojilab.com/zeroteam/ddkafka

细心的同学一定可以发现,执行 go mod init [module]使用 go.mod只有一行信息 module gitlab.luojilab.com/zeroteam/ddkafka,在执行 go build、 go test、 go list 命令时会根据需要的依赖自动生成 require 语句。

现在来说说如何定义一个 modules,modules 是由 Go 源文件目录结构定义的,如果目录下含有 go.mod 文件,该目录称为模块根目录(module root)。模块根目录及其子目录所有的 Go 包都是属于该 modules 的,但是如果子目录包含有了自己的 go.mod 文件就隶属于该 modules。
举一个例子:

 
   
   
 
  1. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  2. $ tree

  3. .

  4. |-- README.md

  5. |-- go.mod

  6. |-- go.sum

  7. |-- models.go

  8. |-- mq_interface.go

  9. |-- sarama

  10. |   |-- sarama_consumer.go

  11. |   |-- sarama_consumer_test.go

  12. |   |-- sarama_producer.go

  13. |   `-- sarama_producter_test.go

  14. `-- segmentio

  15.    |-- segmention_Consumer.go

  16.    |-- segmention_consumer_test.go

  17.    |-- segmention_producer.go

  18.    `-- segmention_producter_test.go

gitlab.luojilab.com/zeroteam/ddkafka目录下含有了 go.mod 文件,所以其子目录 sarama和 segmentio都属于 gitlab.luojilab.com/zeroteam/ddkafka模块,但是如果在 segmentio目录中加入了 go.mod,那么 segmentio 就不再隶属于 gitlab.luojilab.com/zeroteam/ddkafka模块。

那么依赖被下载到哪里了呢,你可以打开的目录 $GPATH/pkg/mod就可以看到了。

主模块和构建列表

The main module and the build list 暂且翻译为主模块和构建列表。
“主模块” 是包含运行 go 命令的目录的模块。 go 命令通过查找当前目录中的 go.mod 或者当前目录的父目录,或者祖父目录,依次递归查找。

go.mod 文件可以通过 require,replace 和 exclude 语句使用的精确软件包集。

  • require 语句指定的依赖项模块

  • replace 语句可以替换依赖项模块

  • exclude 语句可以忽略依赖项模块

go list,可以查看当前的依赖和版本.

 
   
   
 
  1. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)

  2. $ ls  # 这是模块的子目录

  3. segmention_Consumer.go  segmention_consumer_test.go  segmention_producer.go  segmention_producter_test.go

  4. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)

  5. $ go list -m #主模块的打印路径

  6. gitlab.luojilab.com/zeroteam/ddkafka

  7. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)

  8. $ go list -m -f={{.Dir}} #print主模块的根目录

  9. D:\code\gopath\src\gitlab.luojilab.com\zeroteam\ddkafka

  10. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)

  11. $ go list -m all # 查看当前的依赖和版本信息

  12. gitlab.luojilab.com/zeroteam/ddkafka

  13. github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b

  14. github.com/segmentio/kafka-go v0.0.0-20180716203113-48c37f796910

go mod 命令

go mod命令之前可以使用过了 go mod init,下面我们把常用的 go mod命令罗列一下:

  • go mod init: 初始化 modules

  • go mod download: 下载 modules 到本地 cache

  • go mod edit: 编辑 go.mod 文件,选项有 - json、-require 和 - exclude,可以使用帮助 go help mod edit

  • go mod graph: 以文本模式打印模块需求图

  • go mod tidy: 删除错误或者不使用的 modules

  • go mod vendor: 生成 vendor 目录

  • go mod verify: 验证依赖是否正确

  • go mod why:查找依赖

 
   
   
 
  1. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  2. $ go mod edit -json

  3. {

  4.        "Module": {

  5.                "Path": "gitlab.luojilab.com/zeroteam/ddkafka"

  6.        },

  7.        "Require": [

  8.                {

  9.                        "Path": "github.com/golang/glog",

  10.                        "Version": "v0.0.0-20160126235308-23def4e6c14b"

  11.                },

  12.                {

  13.                        "Path": "github.com/segmentio/kafka-go",

  14.                        "Version": "v0.0.0-20180716203113-48c37f796910"

  15.                }

  16.        ],

  17.        "Exclude": null,

  18.        "Replace": null

  19. }

  20. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  21. $ cat go.mod

  22. module gitlab.luojilab.com/zeroteam/ddkafka

  23. require (

  24.        github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b

  25.        github.com/segmentio/kafka-go v0.0.0-20180716203113-48c37f796910

  26. )

  27. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  28. $ go mod edit -require=github.com/Shopify/sarama@master

  29. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  30. $ cat go.mod

  31. module gitlab.luojilab.com/zeroteam/ddkafka

  32. require (

  33.        github.com/Shopify/sarama master

  34.        github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b

  35.        github.com/segmentio/kafka-go v0.0.0-20180716203113-48c37f796910

  36. )

  37. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  38. $ go mod vendor  # 启动verdon

  39. go: downloading github.com/Shopify/sarama v1.17.1-0.20180820172058-647feef69a1a

  40. go: finding github.com/davecgh/go-spew/spew latest

  41. go: finding github.com/eapache/queue v1.1.0

  42. go: finding github.com/eapache/go-xerial-snappy latest

  43. go: finding github.com/eapache/go-resiliency/breaker latest

  44. go: finding github.com/rcrowley/go-metrics latest

  45. go: downloading github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165

  46. go: finding github.com/bsm/sarama-cluster v2.1.15+incompatible

  47. go: downloading github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21

  48. go: downloading github.com/bsm/sarama-cluster v2.1.15+incompatible

  49. go: downloading github.com/eapache/queue v1.1.0

  50. go: finding github.com/eapache/go-resiliency v1.1.0

  51. go: downloading github.com/eapache/go-resiliency v1.1.0

  52. go: finding github.com/davecgh/go-spew v1.1.1

  53. go: downloading github.com/davecgh/go-spew v1.1.1

  54. go: finding github.com/pierrec/lz4 v2.0.3+incompatible

  55. go: downloading github.com/pierrec/lz4 v2.0.3+incompatible

  56. go: finding github.com/golang/snappy latest

  57. go: downloading github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db

  58. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  59. $ ls

  60. README.md  go.mod  go.sum  models.go  mq_interface.go  sarama  segmentio  vendor

  61. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  62. $ go mod verify

  63. all modules verified

  64. qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)

  65. $ go mod why

  66. go: finding github.com/onsi/ginkgo/extensions/table latest

  67. go: finding github.com/onsi/ginkgo v1.6.0

  68. go: finding github.com/Shopify/toxiproxy/client latest

  69. go: finding github.com/onsi/gomega v1.4.1

  70. go: downloading github.com/onsi/gomega v1.4.1

  71. go: downloading github.com/onsi/ginkgo v1.6.0

  72. go: finding github.com/onsi/ginkgo/extensions latest

  73. go: finding github.com/Shopify/toxiproxy v2.1.3+incompatible

  74. go: downloading github.com/Shopify/toxiproxy v2.1.3+incompatible

  75. go: finding github.com/hpcloud/tail v1.0.0

  76. go: finding github.com/golang/protobuf/proto latest

  77. go: finding gopkg.in/yaml.v2 v2.2.1

  78. go: downloading github.com/hpcloud/tail v1.0.0

  79. go: downloading gopkg.in/yaml.v2 v2.2.1

  80. go: finding github.com/golang/protobuf v1.2.0

  81. go: downloading github.com/golang/protobuf v1.2.0

  82. go: finding gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405

  83. go: downloading gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405

  84. go: finding gopkg.in/tomb.v1 latest

  85. go: finding gopkg.in/fsnotify.v1 v1.4.7

  86. go: downloading gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7

  87. go: downloading gopkg.in/fsnotify.v1 v1.4.7

  88. go: finding github.com/fsnotify/fsnotify v1.4.7

  89. go: downloading github.com/fsnotify/fsnotify v1.4.7

  90. # gitlab.luojilab.com/zeroteam/ddkafka

  91. gitlab.luojilab.com/zeroteam/ddkafka

go 的 mod 与 get

go get 这个命令大家应该不会陌生,这是下载 go 依赖包的根据,下载 Go 1.11 出来了,go get 命令也与时俱进,支持了 modules。
go get 来更新 module:

  • 运行 go get -u 将会升级到最新的次要版本或者修订版本

  • 运行 go get -u=patch 将会升级到最新的修订版本(比如说,将会升级到 1.0.1 版本,但不会升级到 1.1.0 版本)

  • 运行 go get package@version 将会升级到指定的版本号

运行 go get 如果有版本的更改,那么 go.mod 文件也会更改。

最后

最后说明一下最新出来的特性不建议立即使用到线上,最好再等等,等迭代一两个版本之后,得带最佳实践出来之后,毕竟现在支持 modules 模式的类库还真不多。

附录

  • https://tip.golang.org/cmd/go/#hdr-Modulesmoduleversionsandmore

  • https://roberto.selbach.ca/intro-to-go-modules


以上是关于Golang modules 初探的主要内容,如果未能解决你的问题,请参考以下文章

golang包管理解决之道——go modules初探

golang goroutine例子[golang并发代码片段]

解决go: go.mod file not found in current directory or any parent directory; see ‘go help modules‘(代码片段

golang代码片段(摘抄)

代码片段 - Golang 实现简单的 Web 服务器

代码片段 - Golang 实现集合操作