Golang中$GOPATH与$GO111MODULE的选择与使用

Golang中$GOPATH与$GO111MODULE的选择与使用 作为初学者,我想了解使用$GOPATH或$GO111MODULE的最佳实践。go get命令是否需要设置$GOPATH,以便将所有依赖项下载到$GOPATH目录中?

谢谢

9 回复

您提到有可能废弃 GOPATH,但看起来至少 go get 命令可能还需要它。那么我想知道,一旦我们不再使用 GOPATH,是否会有其他方式来实现 go get 的功能?

感谢您的分享,您的见解非常具有启发性!

更多关于Golang中$GOPATH与$GO111MODULE的选择与使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


即使现在,我不仅对这些句子感到更加痛苦,更对GOPATHGO111MODULE之间的混淆感到困惑😂

go get命令不仅会下载程序,还会进行编译并将编译后的二进制文件放入$GOPATH/bin中吗?

由于我现在使用Goland IDE,并且假设这些go工具(我可以将golangci-lint视为go工具之一吗)都由IDE自动处理,使用go get的情况就更少了。同意吗?

  1. 是的,go get 仍然需要 GOPATH

  2. 你仍然需要设置 GOPATH,这并非出于开发原因,而是为了维护 go get 的二进制分发机制。例如,要安装 golangci-lint 这个 Go 程序,我们仍然使用:

    $ go get -u github.com/golangci/golangci-lint/cmd/golangci-lint
    
  3. 然而,展望未来,你的开发工作应该坚持使用模块(使用 go.mod 文件)。这也意味着你很少会使用 go get,除非是为了安装一些开箱即用的 Go 程序(如第 2 点所示)。

你提到有可能淘汰 GOPATH,但看起来至少 go get 命令仍需要它。我想知道一旦我们放弃 GOPATH,是否会有其他方式来实现 go get 的功能?

我坚信为了向后兼容,go get 命令会保持原样。即使在 Go 1.13 版本中,它也只是进行了升级而非被替换。

我预计只有底层的 GOPATH 机制会发生变化。这需要一些时间,因为并非所有人都已使用模块功能,完成这种过渡并非易事。

不必担心。当真正要淘汰 GOPATH 时,将会发布重大公告。

感谢 @hollowaykeanho。还有一些后续问题。

  1. 如果我们使用 go get 下载一个开箱即用的程序到 GOPATH 目录,当我们需要这个程序时,GO 是否会自动在 GOROOTGOPATH 中搜索它?

  2. 我认为我们也可以使用 go get 为我们的项目下载包或依赖项,由于我们使用的是 GO111MODULE,通常不使用 GOPATH 目录,GO 如何知道在哪里找到这些为项目下载的依赖项?GO 是否也会自动在 GOPATH 中搜索我们项目使用的任何依赖项(我认为不会)?

  3. go get -u,根据我的理解,这里的 -u 表示更新,会将您的本地更新发送到 github(在这个例子中)。如果我们没有任何更新 github 的计划,是否需要使用 -u?我看到大多数人使用 -u,所以想在这里澄清一下。

jameswang2015:

go get 不仅会下载程序,还会进行编译并将编译后的二进制文件放入 $GOPATH/bin 吗?

是的,自动完成。你会在 GOPATH/src 中获得源代码,在 GOPATH/bin 中获得二进制文件。

jameswang2015:

既然我现在使用 Goland IDE,并且假设这些 go tools(我可以将 golangci-lint 视为 go tools 之一吗)都由 IDE 自动处理,那么使用 go get 的情况就更少了。同意吗?

关于使用 go get 获取 Go 编程工具,这超出了我的了解范围。这取决于 IDE 的健壮性。我无法深入回答 IDE 部分,因为我是一个过时的 Linux vi 用户,仍然在编写最多 80 列的代码。

不,你仍然需要熟悉 go get。它只是一个简单、基本且分发 Go 程序的另一种方式(那些包含 main 代码的程序,比如非常有用的 Hugo)。在以下情况下你仍然需要它:

  1. 开发任何 CI 或基础设施工具。使用官方安装程序或通过 Docker 镜像变通处理的情况除外。
  2. 在严格且过时的系统上生存(比如我使用的稳定版 Debian),由于许多原生软件包都已过时,这种方式很重要。
  3. 快速下载最新版本的 Go 程序,无需处理那些繁琐的打包事宜,比如支付每年 125 美元 / 25 美元的会员费以及签署像我汽车保险杠一样厚的协议。
  4. 作为分发你的 Go 程序的最后手段。

jameswang2015:

即使现在,我不仅觉得这些句子更让人头疼,而且对 GOPATHGO111MODULE 之间的混淆更感到困惑。

太长不看版:

  1. 请设置 GOPATH 并顺其自然
  2. 使用模块进行开发;使用 go get 下载程序
  3. 有疑问?尽管再问
  4. 不要给自己太大压力;放松一下,喝杯绿茶。

Go 是一个非常强大的工具。让时间来滋养你。欢迎加入,Gopher!🚀🎆

jameswang2015:

如果我们使用"go get"下载一个开箱即用的程序到GOPATH目录,当我们需要这个程序时,GO会自动在GOROOT和GOPATH中搜索它吗?

当你需要使用像示例中这样的Go程序时(这是一个强大的linter来检查你的Go源代码),它会自动在GOPATH中搜索。任何编译后的二进制文件都存储在GOBIN下,这本质上是GOPATH/bin

jameswang2015:

我认为我们也可以使用go get为我们的项目下载包或依赖项,由于我们使用GO111MODULE通常不使用GOPATH目录,GO如何知道在哪里找到这些为项目下载的依赖项?GO是否也会自动在GOPATH中搜索我们项目使用的任何依赖项(我认为不是这样)?

模块使用不同的机制来组织依赖项。据我理解,它不再使用GOPATH(这是目标)。模块高度依赖go.mod文件的require子句来提供依赖项列表。更多信息,我建议你花些时间阅读这些文档,并用一些虚拟仓库进行深入实验:

  1. 模块 · golang/go Wiki · GitHub
  2. 使用Go模块 - Go编程语言

附注:我仍在等待开发人员的指示,以便最终放弃GOPATH。到目前为止,我仍然在GOPATH中安装二进制文件。

jameswang2015:

go get -u,根据我的理解,这里的-u表示更新,会将你的本地更新发送到github(在这个例子中)。如果我们没有任何更新github的计划,是否需要使用-u?我看到人们大多使用-u,所以想在这里澄清一下

简单来说,-u参数是从Github拉取最新内容到你的本地仓库,并重新编译相应的二进制文件(如果有的话)。这不是相反的方向。因此,名称update代表"更新你的本地仓库"。

要从本地仓库推送到Github,你使用传统的方式进行开发,即进入目录并执行git push。(你能感受到我们在go模块之前的痛苦吗,过去仅仅通过阅读那句话?)

如果你使用较新的Go版本,比如最新版本,请忽略这一点。请使用模块。

在Go语言中,$GOPATH$GO111MODULE是管理依赖和项目结构的重要机制。随着Go模块(Go Modules)的引入,$GO111MODULE成为现代Go开发中的推荐方式。以下是详细解释和示例代码。

1. $GOPATH 的作用和使用

$GOPATH是Go早期版本中用于管理项目依赖和工作区的环境变量。它定义了三个子目录:src(源代码)、pkg(编译后的包文件)和bin(可执行文件)。在模块系统出现之前,所有Go项目都必须位于$GOPATH/src目录下,并且go get命令会将依赖下载到$GOPATH/src中。

示例: 假设$GOPATH设置为/home/user/go,运行go get github.com/example/pkg会将包下载到/home/user/go/src/github.com/example/pkg

export GOPATH=/home/user/go
go get github.com/example/pkg

2. $GO111MODULE 的作用和使用

$GO111MODULE是控制Go模块行为的环境变量,可设置为onoffauto(默认值)。从Go 1.11开始引入模块支持,允许在项目目录外管理依赖,无需依赖$GOPATH。推荐在Go 1.16及以上版本中默认启用模块(即GO111MODULE=on)。

  • GO111MODULE=on:强制使用模块模式,忽略$GOPATH
  • GO111MODULE=off:禁用模块模式,回退到$GOPATH行为。
  • GO111MODULE=auto:如果当前目录或父目录包含go.mod文件,则启用模块模式;否则使用$GOPATH

在模块模式下,依赖项存储在模块缓存中(默认在$GOPATH/pkg/mod),而不是$GOPATH/src

3. 最佳实践和 go get 命令

对于新项目,强烈推荐使用Go模块(设置GO111MODULE=on),因为它简化了依赖管理,支持版本控制,并允许项目位于任意目录。go get命令在模块模式下不需要$GOPATH设置;它会将依赖项下载到模块缓存中,并在go.mod文件中记录依赖。

示例代码: 创建一个新项目目录,初始化模块,并使用go get下载依赖。

# 创建项目目录(无需在GOPATH内)
mkdir myproject
cd myproject

# 初始化Go模块,指定模块名
go mod init myproject

# 启用模块模式(如果未默认设置)
export GO111MODULE=on

# 使用go get下载依赖,例如gin框架
go get github.com/gin-gonic/gin

这会在当前目录生成go.modgo.sum文件,记录依赖信息。依赖项被存储在全局模块缓存中(如$GOPATH/pkg/mod)。

4. 总结

  • 对于初学者,从Go 1.16开始,默认启用模块模式,无需手动设置$GOPATH。项目可以放在任何位置。
  • go get命令在模块模式下不依赖$GOPATH;它使用模块缓存管理依赖。
  • 如果维护旧项目,可能需要设置GO111MODULE=off来兼容$GOPATH

通过采用Go模块,可以避免$GOPATH的复杂性,实现更灵活的依赖管理。

回到顶部