zhangguanzhang's Blog

go mod的基础使用-科普

字数统计: 1.7k阅读时长: 6 min
2020/03/10

go mod由来

文章主要是针对新人来介绍 go mod 是啥以及新手如何使用,老手不用看。现阶段go mod已经完全GA了,你会用了的话会非常方便
像 python 的项目根目录有requirement.txt记录依赖包,nodejs 是packages.json,同样 go 的包管理从早期的go dep(gopkg)到vendor到现在的go mod.
go dep 很早,没有接触过,如果你接触的项目有go dep,看完本文希望你可以学会改造你手上的老项目,vendor则是把包都存放项目的根路径的vendor文件夹里,就像下面。这会导致一个项目很大,多达40M以上。

1
2
3
4
5
6
7
8
9
10
11
$ tree -d -L 1
.
├── cert
├── cmd
├── docs
├── install
├── ipvs
├── net
├── pkg
├── test
└── vendor #文件夹里全部是依赖

go是一个开放的态度下诞生的语言,并没有其他语言那样官方维护一个中心库,go的库大多数都是直接github上的。
开发者把包存放到github上,一般打tag作为版本,master作为pr和修补,定期cut出新tag。这个做法和实际的开发流程一样。在这个环境下,go的包管理不可能单单存放一个版本号,所以go.mod是存放版本号,go.sum记录git的hash值,以防止篡改。
这样并没有依赖包存在项目文件夹里导致项目代码体积过大,用户通过go mod download命令会调用git去拉取依赖,或者直接go run或者go build也会下载。

go mod如何使用

基础配置和相关环境变量

新手的话推荐使用1.13+版本的go,go mod是诞生于1.11版本,在1.13差不多定型了。1.12之前使用gomod的话需要配置环境变量GO111MODULE=on,这样才会开启 go mod,而 1.13 以后变量默认值为auto,会根据项目下的文件夹和文件自动识别是否是go mod。例如下面就是一个纯go mod项目

1
2
3
4
5
6
7
8
9
10
11
api/
docker/
models/
router/
service/
docs/
Dockerfile
go.mod
go.sum
main.go
README.md

如果之前用 vendor 由于依赖在本地,所以刚上手 go mod 的时候会发现go get拉取超时,实际上我们可以配置环境变量让go拉取包的时候走代理过墙,也就是配置GOPROXY。这个变量只有 go mod 启用下才能使用。
同时要注意的一点是,1.13+ 后GOPROXY能配置多个代理地址,1.13之前则只能1个地址,下面是常见的地址

1
2
3
4
export GO111MODULE=on
export GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy/,https://goproxy.io,direct
# or
go env -w GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy/,https://goproxy.io,direct

direct是直连,用于内网开发拉取内网的私有库。默认拉取的时候会从前到后retry,也可以GONOPROXY配置某个不走代理
配置不走GOPROXY的私有库

1
GOPRIVATE=*.a.example.com,*.b.example.com

go env -w key=value 也可以快速配置,但是是用户家目录的配置文件,不是全局的,这点要注意。如果电脑个人使用就无所谓了
同时,也不要像以前以及网上的那些老视频教程那样把项目放在 GOPATH 上,现在 GOPATH 的概念越来越淡化了,不懂go mod下如果还是把项目创建在GOPATH下会容易出错。
同时也不要创建啥src pkg bin目录了,都是过去式了,可以看上面那个 go mod 的项目文件列表,压根没有src啥的。同时不要像网上的老视频里一个项目整好几个demo,day0x或者lesson这样。

终端编译或者run

配置了两个环境变量,项目也是 go mod 的话我们直接 go run main.go 或者 go build 以及 go get 都会自动拉取包,不用担心墙

gomod和vendor共存

现在并不是所有用户都接受gomod,很多开源项目为了兼容新老用户,go mod和vendor都是有的,类似目录

1
2
3
4
5
...
vendor/
go.mod
go.sum
main.go

这样的项目我们编译的时候命令为

1
go build -mod vendor main.go

goland下的使用

分为新建项目和直接打开项目文件作为项目,不要把项目存放在GOPATH

goland新建gomod开局项目

New Project的时候选择 Go Modules(vgo),我们写Proxy就是GOPROXY,勾上Vendoring mode就是上面go mod和vendor共存的项目,如果你自己写新项目就不要勾选vendor了,vendor应该是过去式了。新版本goland里vendor是不可取消,不用管。

goland打开一个项目,或者改造一个项目

如果是打开一个文件夹的项目,或者New Project的时候已经选择了Go Modules(vgo)上面的Go,我们需要配置下面

  • Settings –> GO –> GOPATH –> Project GOPATH下面如果不为空,就选中后点击右边的减号删掉
  • Settings –> GO –> Go Modules(vgo) 勾选Enable Go Modules(vgo) integration,最新版goland会自动识别,可以不管
  • goland的vgo Execute下面如果是PROXY则直接写上Proxy的值,如果是Environment则写GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy/,https://goproxy.io,direct
  • 如果是改造项目的话记得写了Proxy后得重新关闭下goland里的terminal触发下新的环境变量

我们也可以终端操作
1.13 go mod init的话默认会以项目文件夹名为module名,例如下面

1
2
F:\go\Installer>go mod init
go: creating new go.mod: module Installer

执行后go.mod第一行为

1
module Installer

假如我们项目路径为

1
2
3
4
5
6
7
.
|-- api
| |-- ks.go
| `-- machine.go
|-- go.mod
|-- go.sum
|-- main.go

我们要在main.go里引用api包的话就写

1
import "Installer/api"

第一个就是go.mod里第一行的module名,不仅限于一个单词,有的人会以公司网站或者github地址,例如

1
module github.com/zhangguanzhang/Installer

这种名字下我们引用api就是

1
import "github.com/zhangguanzhang/Installer/api"

1.14开始go mod init后面必须接 module 名字

1
2
3
4
5
6
7
8
$ go mod init
go: cannot determine module path for source directory F:\go\test (outside GOPATH, module path must be specified)

Example usage:
'go mod init example.com/m' to initialize a v0 or v1 module
'go mod init example.com/m/v2' to initialize a v2 module

Run 'go help mod init' for more information.

有时候goland里设置改了不一定生效,所以我们得终端执行go mod init触发下,然后关闭goland重开,还不行就删除掉项目下的.idea,然后右击项目文件夹用goland打开。在设置里去配置下GOPROXY之类的。

goland里使用github上的包的话直接写在import里,goland会提示红色,鼠标悬停在上面根据提示按键按下就会自动go get

CATALOG
  1. 1. go mod由来
  2. 2. go mod如何使用
    1. 2.1. 基础配置和相关环境变量
    2. 2.2. 终端编译或者run
    3. 2.3. gomod和vendor共存
    4. 2.4. goland下的使用
      1. 2.4.1. goland新建gomod开局项目
      2. 2.4.2. goland打开一个项目,或者改造一个项目