
Go Mod
1.Go Mod设置
Go mod模块是相关Go包的集合。modules源代码交换和版本控制的单元。go命令直接支持使用modules,包括记录和解析对其他模块的依赖性。modules替换旧的基于GOPATH的方法来指定在给定构建中使用哪些源文件
设置 GO111MODULE off go命令行将不会支持module功能,寻找依赖包的方式将会沿用旧版本那种通过vendor目录或者GOPATH模式来查找。 on go命令行会使用modules,而一点也不会去GOPATH目录下查找。 auto 默认值,go命令行将会根据当前目录来决定是否启用module功能,当modules 功能启用时,依赖包的存放位置变更为$GOPATH/pkg,允许同一个package多个版本并存,且多个项目可以共享缓存的 module
2.go mod 命令
go mod 有以下命令来管理包
| 命令 | 说明 |
|---|---|
| download | download modules to local cache(下载依赖包) |
| edit | edit go.mod from tools or scripts(编辑go.mod) |
| graph | print module requirement graph (打印模块依赖图) |
| init | initialize new module in current directory(在当前目录初始化mod) |
| tidy | add missing and remove unused modules(拉取缺少的模块,移除不用的模 块) |
| vendor | make vendored copy of dependencies(将依赖复制到vendor下) |
| verify | verify dependencies have expected content (验证依赖是否正确) |
| why | explain why packages or modules are needed(解释为什么需要依赖) |
3.go mod 创建项目
在GOPATH 目录之外新建一个目录,并使用
go mod init初始化生成go.mod文件go mod init $ProjectName
go.mod文件一旦创建后,它的内容将会被go toolchain全面掌控。go toolchain会在各类命令执行时,比如go get、go build、go mod等修改和维护go.mod文件
go.mod提供了module,require、replace和exclude四个命令
- module 语句指定包的名字(路径)
- require 语句指定的依赖项模块
- replace 语句可以替换依赖项模块
- exclude 语句可以忽略依赖项模块
package main import "github.com/astaxie/beego" func main(){ beego.Run() }
- 执行
go run test.go运行代码会发现 go mod 会自动查找依赖自动下载并完成go mod tidy,使用mod文件中的内容进行包拉取
4.replace替换依赖项模块
replace protoes => C:\Users\vSphere\go\src\grpc\grpcdemo\protoesgo.mod
module server go 1.14 replace protoes => C:\Users\vSphere\go\src\grpc\grpcdemo\protoes require ( github.com/golang/protobuf v1.4.2 // indirect golang.org/x/net v0.0.0-20190311183353-d8887717615a google.golang.org/grpc v1.29.1 )
5.解决gomod网络问题
网络问题导致不能正常访问golang.org/x下的包,可以使用replace命令来解决问题
错误信息中会有该包的版本号,如果github正常,golang不正常,使用replace命令将github.com/golang代替golang.org/x,保持两边的版本信息一致
go mod edit -replace=golang.org/x/net@xxxxxxxx119x=github.com/golang/net@xxxxxxxxx119a重新再运行go mod tidy就会发现这一个包解决了,如果包多的话,重复使用replace命令
go mod edit -replace=old[@v]=new[@v]整个项目的依赖包都下载在$GOPATH/mod目录下
6.导入外部安装包
包安装的先决条件是要自动处理包自身依赖关系,被依赖的包也会安装到子目录中
使用
go install的包安装在$GOPATH/pkg/目录下,此命令一般会生成静态库文件,放在GOPATH/pkg/目录下,文件扩展名为a
7.repalce的使用场景
(1)替换无法下载的包
一般会分别引用多个路径包,使用replace来让项目使用GitHub上相应的镜像包,添加一条新的replace条目
replace ( github.com/google/uuid v1.1.1 => github.com/google/uuid v1.1.0 golang.org/x/text v0.3.2 => github.com/golang/text v0.3.2go.mod文件中定义的module还是module golang.org/x/text,这个module名字直接决定了import的路径
(2)调试依赖包
有时我们需要调试依赖包,此时就可以使用replace来修改依赖:
replace ( github.com/google/uuid v1.1.1 => ../uuid golang.org/x/text v0.3.2 => github.com/golang/text v0.3.2 )使用本地的uuid来替换依赖包,此时,可以任意地修改../uuid目录的内容来进行调试
(3)使用fork仓库
fork仓库仅仅是临时的做法,一旦开源版本变得可用,则需要尽快切换到开源版本
(4)禁止被依赖
module不希望被直接引用,由于不存在0.0.0版本,所以其他项目直接依赖时会因为无法找到版本而无法使用,replace指令在当前模块不是main module时会被自动忽略。
8.依赖包存储
GOPATH模式下不方便使用同一个依赖包的多个版本。在GOMODULE模式下这个问题得到了解决,因为这两种模式下依赖包的存储位置发生了变化。
在GOPATH模式下,依赖包存储在GOPATH/src下,该目录下只保存特定依赖包的一个版本,而在GOMODULE模式下,依赖包存储在GOPATH/pkg/mod下,该目录可以存储特定依赖包的多个版本
需要注意的是,GOPATH/pkg/mod目录下有一个cache目录,它用来存储依赖包的缓存,简单来说,go命令每次下载新的依赖包都会在该cache目录中保存一份。
GO111MODULE环境变量控制具体模式:
- export GO111MODULE=off 切换到GOPATH模式
- export GO111MODULE=on 切换到GOMODULE模式
GO111MODULE="on" GOMODCACHE="/home/administrator/go/pkg/mod" GOPATH="/home/administrator/go"1.GOPATH依赖包存储
在GOPATH模式下,go get 命令会将依赖包下载到GOPATH/src/google目录下
该命令等同于在GOPATH/src/google目录下执行git clone https://github.com/google/uuid.git ,也就是说GOPATH/src/google/uuid目录下存储的是完整的仓库
2.GOMODULE依赖包存储
在GOMODULE模式下,go get命令会将依赖包下载到GOPATH/pkg/mod目录下,并且按照依赖包的版本分别存放。注:go get 命令不指定特定版本时,默认会下载最新版
想较于GOPATH模式,GOMODULE有两处不同点:
- 依赖包的目录中包含了版本号,每个版本占用一个目录
- 依赖包的特定版本目录中只包含依赖包文件,不包含.git目录
在GOMODULE模式下,只需要下载模块的代码文件,而不必克隆整个仓库
3.包名大小写敏感问题
包名中包含大写字母,在GOMODULE模式下,在存储时会将包名做大小写编码处理,每个大写字母将变成“!+相应的小写字母”,例如“GOPATH/pkg/mod/github.com/!azure”目录中
9.模块代理GOPROXY
GOPROXY,使用
go mod download命令观察请求代理服务器的信息:go mod download -x -json github.com/google/uuid@lastes
- x参数表示打印下载细节,打印信息中的“Dir”并非是上面提到的缓存目录,而是GOPATH/pkg/mod.
10.GOSUMDB工作机制
默认是官方的checksum database,既教研和数据库sum.golang.org
11.私有模块
环境变量GOPRIVATE用于指定私有模块的前缀,多个模块前缀间使用逗号分隔:
GOPRIVATE= *.corp.example.com,rsc.io/private按照此配置,go命令将把所有拥有这些前缀的模块都视为私有,不会从代理服务器下载代码,也不会使用校验服务器来检查下载的代码。比如模块git.corp.example.com/xyzzy、rsc.io/private、rsc.io/private/quux都将被视为私有
私有代理场景
部分企业或许会自建代理服务器,同时代理公开和私有的模块,这时除了使用环境变量GOPRIVATE,可能还需要GONOPROXY和GONOSUMDB来做更精细化 的控制
GONOPROXY和GONOSUMDB的配置格式与GOPRIVATE相同,分别用于指定绕过模块代理、模块校验的前缀。实际上,GOPRIVATE只是GONOPROXY和GONOSUMDB的简便配置,设置GOPRIVATE相当于同时设置了GONOPROXY和GONOSUMDB。
在GO命令行的内部实现中,GONOPROXY和GONOSUMDB的默认值均为GOPRIVATE;
GOPRIVATE = Getenv("GOPRIVATE") GONOPROXY = envOr("GONOPROXY",GOPRIVATE) GONOSUMDB = envOr("GONOSUMDB",GOPRIVATE)go命令字啊决定是否从代理服务器上下载模块时会参考GONOPROXY的配置,在决定是否校验模块时会参考GONOSUMDB的配置,所以一旦显式地配置了 GONOPROXY和GONOSUMDB,将覆盖GOPRIVATE的配置
12.vendor解决离线工程问题
vendor目录可以简单理解成私有的GOPATH目录。项目编译时,编译器会优先从vendor中寻找依赖包,如果vendor中找不到,那么再到GOPATH中寻找
为了固化使用到的golang.org/x/crypto/ssh和github.com/pkg/sftp版本,可以使用vendor机制
在项目example-gsftp根目录下创建一个vendor目录,并把golang.org/x/crypto/ssh和github.com/pkg/sftp存放到此目录中,让其成为项目的一部分
example-gsftp |____vendor/ |____golang.org/x/crypto/ssh/ |____github.com/pkg/sftp/编译时不会受到GOPATH目录的影响,即便GOPATH下也有一个同名但不同版本的依赖包
13..Go程序的编译
go install用于编译并安装指定的代码包以及它们的依赖包,并且将编译后生成的可执行文件放到bin目录下(GOPATH/bin),编译后的包文件放在当前工作区的平台相关目录下。
编译加密
对外发布编译文件时,如果不希望被人看到源代码,可使用
go build -ldflags命令,设置编译参数-ldflags"-w -s"再编译后发布,这样gdb调试时无法看到源码。设置编译参数
-ldflags "-w -s"。其中-w为去掉调试信息(无法使用gdb调试),-s为去掉符号表.go build -ldflags "-w -s" ./hello.go
14.导入项目下的目录包
我们在main目录同级创建一个新的目录cpmpute,在compute目录下新建add.go文件
目录结构:
#tree . ├── compute │ └── add.go ├── concurrency │ ├── channel.go │ └── first_concurrency.go ├── main │ ├── hello.go │ └── main.go ├── reflection │ └── reflection.go └── synch ├── mutex.go ├── rw_mutex.go ├── sync_map.go └── wait_group.goadd.go
package compute type AddOperator interface { /** * 算术增加 */ Add() interface{} } type IntParams struct { P1 int // 加数 P2 int // 被加数 } func (params *IntParams) Add() interface{} { return params.P1 + params.P2 }ma in.go
package main import ( "fmt" "github.com/longjoy/micro-go-book/ch4-feature/compute" ) func main() { params := &compute.IntParams{ P1: 1, P2: 2, } fmt.Println(params.Add()) }通过import引入了xxx/compute包,接着声明并初始化,调用Add()
.
.