How go module “import” works?

此文翻译自官方文档: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 getgo 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.modgo.sum 文件,go会在 go.mod 中新增一个关于该module路径和版本的 requirement语句,如果寻找的这个package不是直接被 main module 使用,这条新加的 requirement 语句后面就会跟上一个 // indirect 的注释

Leave a Comment