1.前言
网上的文章鱼龙混杂,且都只是给结论,你根本不知道谁说的是对的,谁是错的,为了得到可信的结论,于是有了这篇文章,所谓——实践出真知。
2.实验过程
前期准备
在GOPAHT外部建立目录 my-app:
midir my-app
进入my-app,编写程序, vim main.go:
package main
import "github.com/astaxie/beego"
func main() {
beego.Run()
}
1. GO111MODULE="on":
1.1 不在$GOPATH/src目录下
- 开启GO MOD:
go env -w GO111MODULE="on"
- 生成go.mod :
go mod init my-app
-
执行
go mod tidy
,自动下载包到$GOPATH/pkg/mod:
vim $GOPATH/pkg/mod/github.com/astaxie/beego@v1.12.3/beego.go
增加一行 (58行) :
fmt.Println("mod")
当然记得要引入包:import "fmt"
-
执行
go run main.go
可以证明确实读取了 $GOPATH/pkg/mod的beego。 生成 vendor,执行
go mod vendor
my-app下执行
vim vendor/github.com/astaxie/beego/beego.go
,
还是增加一行 (58行) :
fmt.Println("vendor")
如图所示:
- 执行
go run main.go
可以看到此时优先读取了 vendor里面的外部包
1.2 在$GOPATH/src目录下
- 复制my-app的目录到$GOPATH/src目录下
- 执行
go run main.go
可以看到优先读取的还是vendor - 执行
rm -rf vendor
- 再次 执行
go run main.go
依然读的是mod的。
2. GO111MODULE="off"
先执行命令:
go env -w GO111MODULE="off"
此时我的配置如下:
2.1 GO111MODULE="off"且项目不在 $GOPATH/src下
-
还是之前在GOPATH/src下面:
执行
vim $GOPATH/src/github.com/astaxie/beego/beego.go
还是之前的位置,改为
fmt.Println("src")
- 执行
go run main.go
直接读取的是 $GOPATH/src下面的包。
2.2 GO111MODULE="off"且项目在 $GOPATH/src下
- 还是之前在GOPATH/src;
- 在 $GOPATH/src/my-app 执行
go run main.go
发现竟然读的是vendor的。 - 执行:
mv vendor vendor_bak
即去除vendor的影响,再执行go run main.go
这回读取的就是src的了。
3. GO111MODULE="auto"
执行:
go env -w GO111MODULE="auto"
修改后环境变量如下:
3.1 没有go.mod 且项目在$GOPATH/src下
注意:记得要在:GOPATH/pkg/mod, vendor里面的beego包加入了之前的调试语句:
fmt.Println("src")
fmt.Println("mod")
fmt.Println("vendor")
-
目录文件如下:
-
执行
go run main.go
居然报错了:
-
看看$GOPATH/src是否有包,
ls /mnt/d/GoProjects/src/github.com/astaxie/beego
:
包是有的。 -
执行一下:
go get -v github.com/astaxie/beego
-
再运行:
go run main.go
,发现可以了:
-
猜想走的是
$GOPATH/pkg/mod
里面的包,改了一下,vim /mnt/d/GoProjects/pkg/mod/github.com/astaxie/beego@v1.12.3/beego.go
:
-
再运行:
go run main.go
,证实了:
-
开启vendor,目录结构如下:
-
运行:
go run main.go
还是走mod。
查阅资料发现,只要main.go依赖的包用了go.mod,则默认会启用GOMODULE来下载依赖。
3.2 没有go.mod 且项目不在$GOPATH/src下
按3.1的流程跑了一遍,测试结果同上。
-
目录结构:
- 运行:
go run main.go
走的是mod -
开启vendor,目录结构:
- 运行:
go run main.go
还是走的是mod。
意味着,GO111MODULE="auto" 的情况下,只要依赖包包含了go.mod,那么无论有没有vendor,无论在不在$GOPATH/src下,都会开启mod,并走mod的外部引入包。
3.3 有go.mod 且项目不在$GOPATH/src下
-
目录结构:
-
运行:
go run main.go
即有vendor情况下走的是vendor -
我们执行以下命令
mv vendor vendor_bak
去除vendor影响,目录结构:
-
运行:
go run main.go
走的是mod。
3.4 有go.mod 且项目在$GOPATH/src下
-
目录结构:
-
运行:
go run main.go
即有vendor是直接走vendor -
我们执行以下命令
mv vendor vendor_bak
去除vendor影响,目录结构:
-
运行:
go run main.go
走的是mod。
3.结论
1.GO111MODULE="on"
1.1 GO111MODULE="on" 且项目不在 $GOPATH/src下
- 当vendor目录存在,优先读取vendor的外部包
- 当vendor目录不存在,读取$GOPATH/pkg/mod下的外部包
1.2 GO111MODULE="on" 且项目在 $GOPATH/src下
跟上面情况(GO111MODULE="on" 且项目不在 $GOPATH/src下)一致。
2. GO111MODULE="off"
2.1.GO111MODULE="off" 且项目不在 $GOPATH/src下
- 无论有没有vendor,直接读取$GOPATH/src里面的外部引入包,即不会读取vendor里面的包
2.2.GO111MODULE="off" 且项目在 $GOPATH/src下
- 有vendor则读取vendor的外部引入包
- 没有vendor则读取$GOPATH/src里面的外部引入包
3.GO111MODULE="auto"
3.1 没有go.mod 且项目不在$GOPATH/src下
- 没有vendor,且依赖的包里面有go.mod,直接走$GOPATH/pkg/mod
- 没有vendor,且依赖的包里面都没有go.mod,直接走$GOPATH/src (待验证)
- 有vendor,也没有用,只要依赖的包里面有go.mod,还是走$GOPATH/pkg/mod
- 有vendor,且依赖的包里面都没有go.mod,走$GOPATH/src (待验证)
3.2 没有go.mod 且项目在$GOPATH/src下
- 没有vendor,且依赖的包里面有go.mod,直接走$GOPATH/pkg/mod
- 没有vendor,且依赖的包里面都没有go.mod,直接走$GOPATH/src (待验证)
- 有vendor,也没有用,只要依赖的包里面有go.mod,还是走$GOPATH/pkg/mod
- 有vendor,且依赖的包里面都没有go.mod,走vendor (待验证)
3.3 有go.mod 且项目不在$GOPATH/src下
- 有vendor, 则读取vendor的外部引入包
- 没有vendor则读取$GOPATH/pkg/mod里面的外部引入包
3.4 有go.mod 且项目在$GOPATH/src下
与上面的情况(有go.mod 且项目不在$GOPATH/src下)一致。