一、引言
很多go语言的初学者朋友们总是听到go mod init,GOPATH等单词,但是又不知道啥意思,我是从c++转来学golang的,一开始对于这些包管理也很迷茫。查了很多资料但是都懵懵懂懂的,所以我希望这篇文章能对各位初学者有一些帮助。
二、什么是GOPATH?
go 1.11版本以前用的是GOPATH来管理第三方包,那是怎么管理的呢?
假设我有一个项目叫test
,绝对路径是home/go/test
,那么我就需要把这个项目的路径设置为GOPATH,可以使用命令export GOPATH=/home/user/hello
设置好GOPATH。
同时我的test
项目下需要建立三个文件夹,分别命名为src
、pkg
、bin
。他们的作用分别是:
1.src:存放自己编写的go的源码文件
src相当于一个工作区,如:
$GOPATH/src/main/main.go
注意:我们在网上导入的第三方包也是放在$GOPATH/src
目录下。或者自己单独维护一个vendor
目录,隔离项目依赖。
2.pkg:存放编译后的包
go install命令会把生成的包存放在GOPATH/pkg目录中。
3.bin:存放编译生成的可执行文件
go install编译出的可执行文件存放在GOPATH/bin,方便直接运行。
显而易见,GOPATH下必须有三个固定的文件夹,否则go install就不知道该把生成的文件放在哪。
每个项目都可以有自己的GOPATH,依赖可以隔离,避免污染,比如对于上面那个项目,我们可以这样设置:
export GOPATH=/home/user/hello
cd $GOPATH/src
# 编写 hello.go
go install
# 编译生成可执行文件到 bin 目录
$GOPATH/bin/hello
GOPATH决定了Go语言的项目工作区,对组织跨包项目是很重要的。如果我们在需要第三方包的时候,还需要自己导入$GOPATH/src
目录下,非常麻烦。
三、go mod来啦!
上面那种方式被大多数开发人员所诟病,因为太麻烦了,每次运行不同的项目都要切换GOPATH,于是在go 1.11版本之后,出现了go mod。
那么go mod怎么使用呢?
1.go mod init
有了go mod以后,我们不用再创建上面提到的三个固定的文件夹了,比如这时候我有个test
项目,我们可以使用命令:
go mod init test
它的作用是初始化当前文件夹,创建go.mod文件来标识这个模块。
这时候生成了一个名字为go mod的文件,里面包含整个项目的包名test
和go的版本:
这个项目下有个main包和一个compute包。
compute包中分别定义了两个函数叫Add()
和Sub()
//add.go
package compute // 这里的compute是指compute包,命名不一定要和当前文件所在文件夹名字一样
func Add(a int, b int) int {
return a + b
}
//sub.go
package compute
func Sub(a int, b int) int {
return a - b
}
如果我想在main函数中使用这两个函数,那么我需要导入包compute:
//main.go
package main
import (
"fmt"
"test/compute" // test为整个项目的包名
)
func main() {
num1 := compute.Add(2, 3)
num2 := compute.Sub(10, 9)
fmt.Println("num1 = ", num1)
fmt.Println("num1 = ", num2)
}
整个大项目中只能有一个main函数,假设main函数所在的包名叫main,我们运行代码时可以输入:
go run ./main
就可以直接运行整个项目了。
2.go mod tidy
如果我们要导入第三方包怎么办呢?我们可以直接找到github的项目网址,直接在文件开头导入:
package main
import (
"fmt"
"github.com/bytedance/sonic" // 导入第三方包
"test/compute"
)
func main() {
num1 := compute.Add(2, 3)
num2 := compute.Sub(10, 9)
fmt.Println("num1 = ", num1)
fmt.Println("num1 = ", num2)
str, _ := sonic.Marshal("hello")
fmt.Println(string(str))
}
这时候我们需要输入go mod tidy
,这个命令的作用是添加缺少的依赖,删除未使用的依赖:
同时我们点进go mod文件中,发现多了点东西:
module test
go 1.19
require github.com/bytedance/sonic v1.9.2
require (
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
)
require
中就是我们当前项目的依赖,这样就不用我们管理自己管理第三方包了,非常方便。
如果我们在main中把import "github.com/bytedance/sonic"
删掉,不调用这个包了,我们再次输入go mod tidy
,就会清除掉go mod文件中的相关依赖。
3.其它go mod命令
在这里我写一下其它的go mod命令:
- go mod download:下载所有依赖的模块到本地cache。
- go mod vendor:将依赖的模块拷到vendor目录中,实现依赖本地化。
- go mod verify:验证依赖是否匹配,可以发现潜在的问题。
- go mod why:解释为什么需要依赖某个模块。
- go mod graph:打印模块依赖图。
- go mod edit -replace=old@v1.0.0=new@v1.0.1:将某个依赖版本替换为另一个版本。
四、总结
go module完全自动化管理依赖,不再需要手动维护vendor工具。这简化了依赖管理,我们推荐在新的Go项目中使用go module。