今天在看一个程序代码,发现里面用到了grpc,程序的目录结构是这样的
onlineClean | 包名main | ||
---|---|---|---|
main.go | |||
go.mod | |||
proto | |||
structs.go | 包名proto | ||
rpcClient | 包名main | ||
test.go |
其中rpcCleint/test.go里面有这样的代码
import (
"fmt"
pb "onlineClean/proto"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
当时我觉得有点奇怪,在rpcClient里面这样引用onlineClean/proto,可以编译过吗?
于是试验了一下,在rpcCleint下执行go build(go 版本是1.14),发现还真可以编译成功。
当时我就在想,go build寻找import的包过程是怎么样的呢? 它是怎么发现onlineClean/proto这个包的
很明显,这里go build时应该是从rpcClient的上层目录开始找onlineClean/proto的,那为啥它是从上层目录找而不是当前目录找呢?
上网找了一下,网上文章是这样说的:
在我们引入第三方的时候,其会在三个地方区查找
1、GOROOT路径
2、GOPATH路径
3、在原目录中的vendor目录下进行查找
里面没提到会从上级目录找。
我检查了一下GOROOT和GOPATH变量(go env GOROOT和go env GOPATH),发现都没有包含onlineClean或者../目录
感觉网上说的可能不太全,或者网上的资料太旧了,不适合1.14。
后来,偶然间,我发现把rpcClient复制到其它目录(与onlineClean并列),就编译不了。编译提示“go: cannot find main module; see 'go help modules'”
然后我对比了在onlineClean/rpcClient和rpcClient两个目录执行go env的区别,发现主要是GOMOD环境变量的区别:
在onlineClean/rpcClient,会输出set GOMOD=D:\ht\软件部\数据质量管控平台\代码\华为云\go\onlineClean\go.mod
而在rpcClient则没有输出这个环境变量。
于是我猜测,开启go mod时go build时会向上找go.mod,找到后使用这个go.mod进行第三方包管理,查了一下go mod的帮助文档,证实了我这个猜测。
go helo go.mod
A module version is defined by a tree of source files, with a go.mod
file in its root. When the go command is run, it looks in the current
directory and then successive parent directories to find the go.mod
marking the root of the main (current) module.
这段话大概是说:当go命令运行,会先查找当前目录有没有go.mod,如果没有会一直向上找,直到找到go.mod,并以找到go.mod的目录做为根目录进行第三方包引用 。