为什么 "go get" 失效了以及如何修复?
\n如果你曾经问过 "How can I install a package with go get?" — 你并不孤单。这个问题在 Stack Overflow 上获得了数千次浏览,这并非没有原因。以前一切都很简单:go get github.com/some/package — 然后库就会出现在你的 $GOPATH/src 中。但在 Go 1.16 发布之后,一切都变了。现在 go get 不再以传统意义安装包。相反,它只更新 go.mod。而安装二进制文件则出现了 go install 命令。
在本文中,我们将探讨发生了什么,现在如何正确地安装包和依赖项,以及为什么新手经常感到困惑。我们开始吧!
\n\n简史:从 GOPATH 到模块
\n在 Go 1.11 版本之前,所有代码都存在于 GOPATH 中——一个存放你所有项目和第三方包的特殊文件夹。go get 命令会直接将源代码下载到那里。这很方便,但带来了版本问题:如果两个项目需要同一个库的不同版本——麻烦就开始了。
随着 Go 模块(从 Go 1.11 开始,并在 1.16 中稳定)的到来,每个项目都拥有了自己的 go.mod 文件——其中列出了依赖项及其版本。现在 go get 的工作方式不同了:
- \n
- 添加依赖项到
go.mod\n - 下载到缓存(通常是
$GOPATH/pkg/mod) \n - 不在
$GOPATH/bin中创建二进制文件 \n
如果你需要安装一个现成的程序(例如,命令行工具)——请使用 go install。
go get 现在如何工作:逐步解析
\n打开终端并创建一个新模块:
\nmkdir myproject\ncd myproject\ngo mod init myproject\n现在假设我们想添加一个流行的路由库 gorilla/mux。以前我们会写:
go get github.com/gorilla/mux\n这仍然有效——库会被下载。但看看发生了什么:
\n- \n
- 在
go.mod中出现了一行:require github.com/gorilla/mux v1.8.0\n - 在项目文件夹中出现了
go.sum文件——用于安全性的校验和文件 \n - 库的源代码位于缓存中,而不是项目旁边 \n
现在你可以在代码中导入该包:
\npackage main\n\nimport (\n "fmt"\n "github.com/gorilla/mux"\n)\n\nfunc main() {\n r := mux.NewRouter()\n fmt.Println("Router created!")\n}\n运行 go run main.go — 一切正常。但如果你想要一个二进制文件(编译后的程序)—— go get 不会提供给你。
安装二进制文件:go install 前来帮忙
\n假设你找到了一个很棒的 Go 工具,例如 golangci-lint —— 一个代码检查工具。要将其作为系统命令安装,以前会写:
go get github.com/golangci/golangci-lint/cmd/golangci-lint\n现在这不会起作用(会发出警告)。正确的方法是:
\ngo install github.com/golangci/golangci-lint/cmd/golangci-lint@latest\n会发生什么:
\n- \n
- Go 会下载该工具的源代码 \n
- 编译它们 \n
- 将生成的二进制文件放入
$GOPATH/bin(如果设置了环境变量,则放入$GOBIN) \n
确保 $GOPATH/bin 已添加到 PATH 中——否则该命令将不可用。可以这样检查:
echo $GOPATH\n# 通常是 /home/user/go\nls ~/go/bin/\n如果那里有你的二进制文件——那就没问题了。
\n\n新手常见错误(以及如何避免)
\n在 Stack Overflow 上,最常见的问题是关于这些陷阱:
\n- \n
- "go get 没有创建 src 文件夹"
博客
书籍推荐
推荐阅读