此文翻译自官方文档:https://go.dev/ref/mod#resolve-pkg-mod
当你使用 import xxx 方式导包时,它首先需要判断这个包来自哪个module
go首先会在 build list寻找是否有哪个module的前缀与导入的包前缀的相同,例如,如果你想导入 example.com/a/b
,并且 example.com/a
存在与 build list(go.mod中列出的依赖,类似 package.json 或者 build.gradle 这种),然后go将会检查 example.com/a
是否存在b
这个目录,且其下面至少包含一个go文件。如果在build list中找到匹配的module的话就使用它,如果没找到或者找到了多个module都提供了这个package(为啥会这样?),go就会报错。但如果设定了-mod=mod
参数的话,go就会尝试去寻找这个包,go get
和 go mod tidy
命令会自动做这件事情
怎么找呢?它会首先检查 GOPROXY
这个环境变量,该命令可以设置多个代理地址,使用逗号分开。或是将其设置为 off
,表示不使用代理。
他会遍历所有的代理地址,并寻找所有可能提供该pkg的module(就是所有的pkg前缀都当作module名尝试寻找),对于每个可能的module,go都会将其最新版本下载下来,并且去看它是否真的提供所需的pkg。如果有多个module都提供了这个包,则以名称长的那个module为准。如果都不提供或者找不到可能的module,则报错。
例如:你的代码中
import golang.org/x/net/html
并且
GOPROXY=https://corp.example.com,https://proxy.golang.org
go就会同时在两个代理服务器中找:
- 在 https://corp.example.com/ 中(并发寻找多个可能的module):
- golang.org/x/net/html
- golang.org/x/net
- golang.org/x
- golang.org
如果在第一个代理服务器中没找到,则继续按上述寻找方式在第二个代理服务器中找,以此类推
找到后则会下载并更新 go.mod
和 go.sum
文件,go会在 go.mod
中新增一个关于该module路径和版本的 requirement
语句,如果寻找的这个package不是直接被 main module 使用,这条新加的 requirement 语句后面就会跟上一个 // indirect
的注释