• Welcome to Journal web site.

我是 PHP 程序员

- 开发无止境 -

Next
Prev

go mod和GOPATH的区别

Data: 2018-04-08 05:08:05Form: JournalClick: 28

一、引言

很多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。他们的作用分别是:

  • src:存放自己编写的go的源码文件 src相当于一个工作区,如: $GOPATH/src/main/main.go 。注意:我们在网上导入的第三方包也是放在$GOPATH/src目录下。或者自己单独维护一个vendor目录,隔离项目依赖
  • pkg:存放编译后的包 go install命令会把生成的包存放在GOPATH/pkg目录中。
  • 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/so"删掉,不调用这个包了

我们再次输入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。

Name:
<提交>