理解GoPath管理项目依赖、版本与Go mod的使用 文章 2021-09-02 11:17:40 +0800 CST 阅读:3297 评论数:0 [TOCM] [TOC] ### 前言 我觉得对于初学者来说,很有必要了解Go在项目中的目录结构设计,以及依赖管理,在学习之初我受了各大教程比较深入的影响,在各大网站上的教程,大多数都停留在go 1.1.1版本之前,他们是这样讲的: **一个Go语言项目的目录一般包含以下三个子目录:** - src 目录:放置项目和库的源文件; - pkg 目录:放置编译后生成的包/库的归档文件; - bin 目录:放置编译后生成的可执行文件。 #### 疑问 1. 这样岂不是每一个项目都需要一个GOPATH,开发就必须在src下? 就像这样? ``` ├── bin ├── pkg └── src └── main.go ``` 2. 通过go get 下载的三方包都在此工作区,并且没有版本控制,如果我要更新三方包的话我该如何处理? 3. 如果要建立多个项目,是不是就要建立多个GOPATH,要使用到同一个包,是不是又要重新go get 一次? #### 汇总 初学时,我感觉项目光是这样的目录设计让我有很多疑问,也比较费解。 #### 解决 后来带着疑问查了一些资料,发现1.11后`go mod`可以很方便的解决这一系列的问题。 ### go mod go modules 是 golang 1.11 新加的特性。要使用它需要升级版本 >= 1.11 #### go mod 的定义 gomod 官方是这样定义的: > 模块是相关Go包的集合。modules是源代码交换和版本控制的单元。 go命令直接支持使用modules,包括记录和解析对其他模块的依赖性。modules替换旧的基于GOPATH的方法来指定在给定构建中使用哪些源文件。 #### go mod 说明 当modules功能启用时,依赖包的存放位置变更为$GOPATH/pkg,允许同一个package多个版本并存,且多个项目可以共享缓存的 module > 这里也是就是说,现在我们如果有多个项目都可以使用go mod 来使用$GOPATH/pkg 下的依赖包了,再也不用每个项目中都来一个pkg 目录。 #### go 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. ``` #### go mod 的使用 ##### 设置GO111MODULE为on ```go go env -w GO111MODULE=on ``` ##### 开启代理 ```go go env -w GOPROXY="https://goproxy.io,direct" ``` ##### go env 查看环境配置 ``` go env #结果如下 GO111MODULE="on" GOARCH="amd64" GOBIN="" GOCACHE="/Users/tangyijun/Library/Caches/go-build" GOENV="/Users/tangyijun/Library/Application Support/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="darwin" GOINSECURE="" GOMODCACHE="/Users/tangyijun/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="darwin" GOPATH="/Users/tangyijun/go" GOPRIVATE="" GOPROXY="https://goproxy.io,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64" GOVCS="" GOVERSION="go1.16.6" GCCGO="gccgo" AR="ar" CC="clang" CXX="clang++" CGO_ENABLED="1" GOMOD="/dev/null" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/jz/2z_04nps7bg3d7c8kpgkp8fc0000gn/T/go-build1024950328=/tmp/go-build -gno-record-gcc-switches -fno-common" ``` ##### 在项目中初始化 ``` #创建一个go项目目录并且进入 mkdir gobloger && cd gobloger go mod init gobloger #名称 ``` 此时就会自动创建一个go.mod 文件 ``` └── go.mod ``` 其内容为 ``` module gobloger go 1.16 ``` ##### 接下来我们创建一个main.go 文件 此时可能会出现一些问题如下图  这是因为这个包在其他项目中`go get` 过了。 - 最后大家打开go.mod 文件可以发现内容是这样的: ``` module gobloger go 1.16 require github.com/gin-gonic/gin v1.7.4 ``` - 使用go mod tidy > 命令会检查包,并且整理,拉取项目中用到的包,删除多余的包 ### 总结 - go.mod文件一旦创建后,它的内容将会被go toolchain全面掌控。go toolchain会在各类命令执行时,比如go get、go build、go mod等修改和维护go.mod文件。 - 因此我们基本上不需要手动去更改他,比如执行,go get 版本更新这些都会对go.mod文件进行修改。 - 使用go mod 之后我们会发现我们go get 下载的依赖包都会在我们的GOPATH/pkg /mod下,我们来看下现在的目录 ``` ├── pkg │ ├── mod │ │ ├── cache │ │ ├── github.com │ │ ├── golang.org │ │ ├── google.golang.org │ │ └── gopkg.in │ └── sumdb │ └── sum.golang.org ``` - 现在用 go mod 来管理依赖包,不管有多少个项目我们都可以用同一个GOPATH的依赖,并且我们再也不需要原本的定式目录结构。 不知道看到这个 `go mod` 的小伙伴有没有想起来php中的`composer` 没错,就是那么异曲同工。