舍近求远,为什么 Golang 要这样读取本地的 package?

我们知道,Python 的第三方库一般是托管到 Pypi 上面的,使用 pip 命令进行安装。而 Golang 很多第三方库是托管在 Github 上面的,使用 go get 进行安装。

有时候,我们会发现一个很奇怪的现象,很多 Golang 的项目,在引用自己项目里面的包的时候,竟然用的是 Github 上面的地址。

例如我们看这个项目:https://github.com/kingname/handsome ,它的入口文件是main.go。我们打开这个文件,会看到里面import语句中,从 Github导入自身的util包:

可问题是,这个 util文件夹就在main.go旁边啊:

如果是在 Python 里面,入口文件main.py旁边有一个util文件夹,这个文件夹里面有一个util.py的文件,那么我们直接写from util.util import xxx就可以导入util.py文件中的函数了。为什么 Golang 里面要从 Github 导入?那如果我更新了util/util.go文件里面的内容,但是我没有把这次修改上传到 Github 中,当我运行go run main.go的时候,运行的是老代码还是新代码?用的是我本地的版本还是 Github 上面的版本?

这个问题的关键,就在go.mod这个文件中。打开请看这个文件的第一行:

可以看到,这个项目是使用 go mod 进行管理的,并且指定这个模块的名字,就叫做github.com/kingname/handsome

所以,当我们执行命令go run main.go的时候,Golang 的编译器知道自己就是github.com/kingname/handsome,那么main.go里面导入github.com/kingname/handsome/util,实际上就是本项目自身根目录的 util文件夹中的包,它不会发起网络请求,不会从 Github 上面重新下载。每次运行的时候,使用的总是项目util/util.go中的内容。

但是,如果你现在在另外一个项目里面导入github.com/kingname/handsome/util,Golang 从go.mod中知道当前运行的项目跟即将导入的这个包不在同一个项目中,于是它就会去 Github 上面拉代码下来运行。

这个规则,可以在 Golang 的官方文档Module paths这一节找到:Go Modules Reference - The Go Programming Language