这是一篇关于讲解Go Moudule基础概念的博客

1. 什么是 Go Module

go依赖包最初是monorepo模式,所有的包都放在 GOPATH 里面,使用类似命名空间的包路径区分包,不过这种包管理显然是有问题,由于包依赖可能会引入破坏性更新,生产环境和测试环境会出现运行不一致的问题。
在Go语言快速发展的过程中也出现了一些比较优秀的依赖管理工具,比如 govendor、dep、glide 等,但是这些工具都还是需要依赖于GOPATH,在v1.11中加入了 Go Module 作为官方包管理形式。不过在 v1.11 和 v1.12 的 Go 版本中 gomod 是不能直接使用的。可以通过go env命令返回值的 GOMOD 字段是否为空来判断是否已经开启了 gomod,如果没有开启,可以通过设置环境变量 export GO111MODULE=on开启gomod。目前gomod在Go v1.12功能基本稳定,目前从版本 v1.13 将默认开启,查看方法:

➜  ~ go env | grep -i MODULE
GO111MODULE="on"

2. 启动测试容器,创建一个go项目执行来理解go mod

docker run -itd --rm --name golang golang:1.16.3-alpine3.13
docker exec -it golang sh
/go # cd src/ && mkdir Testapp && cd Testapp
/go # vi test.go
package main
import (
	"fmt"
	"github.com/Pallinder/go-randomdata"
)
func main(){
	fmt.Println("running app ok")
	fmt.Println(randomdata.SillyName())
}

3. 尝试执行test.go

/go/src/Testapp # go run test.go
test.go:4:2: no required module provides package github.com/Pallinder/go-randomdata: go.mod file not found in current directory or any parent directory; see 'go help modules'

报错提示在当前目录或任何父目录中找不到Mod文件,解决办法是要将Go模块初始化为应用程序执行

4. go mod init Testapp(项目名称),生成go.mod文件

/go/src # alias ll="ls -l"
/go/src # ll
total 4
drwxr-xr-x    2 root     root          4096 Jan  1 12:56 Testapp
/go/src/Testapp # go mod init Testapp
go: creating new go.mod: module Testapp
go: to add module requirements and sums:
	go mod tidy
/go/src/Testapp # ll
total 8
-rw-r--r--    1 root     root            24 Jan  1 13:22 go.mod
-rw-r--r--    1 root     root           152 Jan  1 11:32 test.go

/go/src/Testapp # cat go.mod
module Testapp

go 1.16

再次 go run运行它,这里会告诉我们没有依赖的模块

5. 运行go get 包

/go/src/Testapp # go run test.go
test.go:4:2: no required module provides package github.com/Pallinder/go-randomdata; to add it:
	go get github.com/Pallinder/go-randomdata
```/go/src/Testapp # go get github.com/Pallinder/go-randomdata
go get: module github.com/Pallinder/go-randomdata: Get "https://proxy.golang.org/github.com/%21pallinder/go-randomdata/@v/list": dial tcp 142.251.42.241:443: i/o timeout

6. go get 包网络不通解决办法:

请求的是proxy.golang.org,这个地址默认是国外无法连通,使用国内的维护的goproxy.cn,这个是中国受信任的go modules管理开源地址,需要使用此代理解决此问题 -u 强制使用网络去更新包和它的依赖包 -v 显示执行的命令

/go/src/Testapp #  export GOPROXY=https://goproxy.cn
/go/src/Testapp #  go get -u -v github.com/Pallinder/go-randomdata
go: downloading github.com/Pallinder/go-randomdata v1.2.0
github.com/Pallinder/go-randomdata
go get: added github.com/Pallinder/go-randomdata v1.2.0

go get之后go.sum的文件更新正在使用的程序包的代码库和版本。

/go/src/Testapp # cat go.mod
module Testapp

go 1.16

require github.com/Pallinder/go-randomdata v1.2.0 // indirect
/go/src/Testapp # cat go.sum
github.com/Pallinder/go-randomdata v1.2.0 h1:DZ41wBchNRb/0GfsePLiSwb0PHZmT67XY00lCDlaYPg=
github.com/Pallinder/go-randomdata v1.2.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y=

go.sum是针对每个依赖项上都有一个加密哈希。如果第三方库具有多个版本,并且想使用其他版本,则可以更改版本号go get再次运行。假设我想改用v1.1.0的go-randomdata,可以用@v1.1.0指定版本(go get package@version),在gopath下能看到刚刚拉下来的两个版本的依赖包

/go/src/Testapp # go get -u -v github.com/Pallinder/go-randomdata@v1.1.0
go: downloading github.com/Pallinder/go-randomdata v1.1.0
github.com/Pallinder/go-randomdata
go get: downgraded github.com/Pallinder/go-randomdata v1.2.0 => v1.1.0
/go/src/Testapp # cat go.mod
module Testapp

go 1.16

require github.com/Pallinder/go-randomdata v1.1.0 // indirect

/go/src/Testapp # go env | grep -i gopath
GOPATH="/go"
/go/src/Testapp # ls -ld /go/pkg/mod/github.com/!pallinder/go-randomdata@v1.*
dr-xr-xr-x    3 root     root          4096 Jan  1 13:42 /go/pkg/mod/github.com/!pallinder/go-randomdata@v1.1.0
dr-xr-xr-x    3 root     root          4096 Jan  1 13:38 /go/pkg/mod/github.com/!pallinder/go-randomdata@v1.2.0

7. 一键解决所有依赖

go mod tidy

8. 最后运行正常,符合预期

/go/src/Testapp # go run test.go
running app ok
Legendviridian

9. 使用go help mod查看go mod其他参数方法

/go/src/Testapp # go help mod
Go mod provides access to operations on modules.

Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.

Usage:

	go mod <command> [arguments]

The commands are:

	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

Use "go help mod <command>" for more information about a command.

10. go mod vendor介绍

使用go mod vendor将项目的依赖库下载到项目内部,作为项目的一部分来编译(注意依赖需要在import 中声明后才能进行导入),一般用于无法连接github或者gitlab环境本地修改源码方式,本地实时编译实时测试的方式 执行完go mod vendor之后,当前项目Testapp的依赖包将自动从GOPAT依赖的 /go/pkg/mod/github.com/!pallinder/go-randomdata@v1.2.0跳转到vendor目录下的/go/src/Testapp/vendor/github.com/Pallinder/go-randomdata

/go/src/Testapp # ll
total 12
-rw-r--r--    1 root     root           118 Jan  1 14:44 go.mod
-rw-r--r--    1 root     root           449 Jan  1 14:44 go.sum
-rw-r--r--    1 root     root           173 Jan  1 14:09 test.go
/go/src/Testapp # go mod vendor
/go/src/Testapp # ll
total 16
-rw-r--r--    1 root     root           118 Jan  1 14:44 go.mod
-rw-r--r--    1 root     root           449 Jan  1 14:44 go.sum
-rw-r--r--    1 root     root           173 Jan  1 14:09 test.go
drwxr-xr-x    3 root     root          4096 Jan  1 14:49 vendor

/go/src/Testapp # go env | grep -i path
GOPATH="/go"
/go/src/Testapp # ll /go/pkg/mod/github.com/!pallinder/go-randomdata@v1.2.0/
/go/src/Testapp # ll /go/src/Testapp/vendor/github.com/Pallinder/go-randomdata

/go/src/Testapp # go run test.go
running app ok
Chatterring

11. 总结

go mod是解决go的依赖包的管理工具,新建项目时候需要使用 go mod init 项目名生成go.mod文件,使用go get 包获取项目依赖包并写入到go.mod和go.sum文件中,也可以使用go mod tidy一键解决所有依赖包(删除不依赖的包)