确实不再需要GOPATH和GOROOT了吗?

碰巧的是,刚开始熟悉Go的开发人员经常会遇到为Go项目选择工作目录的问题。 因此, 在GolangConf会议的聊天中 ,也提出了这个问题。 新来的地鼠经常用“ GOPATH”和“ GOROOT ”一词互相吓scar 。 但是,在当前版本的Go(1.13)的快速入门指南中,根本没有提到这两个“吓人”字眼。


让我们看看为什么。 为了使实验更纯净,我将新的Ubuntu部署到虚拟机上,并根据Wiki的说明安装了Go:


sudo add-apt-repository ppa:longsleep/golang-backports sudo apt-get update sudo apt-get install golang-go 

Go 1.13已安装并可以使用:


 $ go version go version go1.13 linux/amd64 $ which go /usr/bin/go $ whereis go go: /usr/bin/go /usr/lib/go /usr/share/go /usr/share/man/man1/go.1.gz 


关于GOROOT已经在2015年的文章中完美撰写,但这些信息仍然有用。


有趣的是,在最后一个命令( whereis go )发出的目录列表中, GOROOT实际上不是:


 $ go env GOROOT /usr/lib/go-1.13 

因此,例如,如果对于IDE,我需要指定标准Go库文件的路径,则将指定/usr/lib/go-1.13 。 也许,在这种情况下, GOROOT在日常生活中的使用就结束了。


GOPATH和模块


似乎在这个地方有必要急于安装GOPATH ,但是我不会这样做。 实际上已经设置了GOPATH


 $ go env GOPATH /home/elena/go 

我对~/goGOPATH感到满意,这意味着我不会更改它。


我将立即为Go上的第一个项目创建目录。 这可以在任何位置完成,例如在您的主目录中。 另外,我将立即开始使用Go Modules工具:


 $ mkdir ~/hello $ go mod init github.com/rumyantseva/hello go: creating new go.mod: module github.com/rumyantseva/hello 

对于go mod init命令,我为项目指定了唯一的模块模块路径。 这样,如果需要,代理或其他工具可以找到我项目的文件。


调用go mod init命令后, go mod init目录出现在我的主目录中:


 $ tree ~/go /home/elena/go └── pkg └── mod └── cache └── lock 3 directories, 1 file 

在这种情况下,锁定文件(在树的最底部)仍然为空。


go.mod文件出现在~/hello go.mod具有以下内容:


 module github.com/rumyantseva/hello go 1.13 

go.mod ,将随后存储有关模块依赖项的所有信息。


现在让我们使用外部依赖关系编写一个应用程序。 在~/hello目录中,我创建main.go文件,并将以下代码写入其中:


 package main import ( "github.com/sirupsen/logrus" ) func main() { logrus.Info("Hello, world!") } 

在现实生活中当然会写“你好,世界!” 您可以不用logrus进行操作 ,但是在此示例中,该库将帮助我们找出外部依赖文件的存储位置。


我以最简单的方式启动应用程序:


 $ go run main.go go: finding github.com/sirupsen/logrus v1.4.2 go: downloading github.com/sirupsen/logrus v1.4.2 go: extracting github.com/sirupsen/logrus v1.4.2 go: downloading golang.org/x/sys v0.0.0-20190422165155-953cdadca894 go: extracting golang.org/x/sys v0.0.0-20190422165155-953cdadca894 go: finding golang.org/x/sys v0.0.0-20190422165155-953cdadca894 INFO[0000] Hello, world! 

在构建和启动应用程序之前, go mod工具已经起作用。 他定义了我的外部依赖项github.com/sirupsen/logrus ,获取了最新版本v1.4.2并用于传递性依赖项。


go.mod文件中添加了go.mod ,描述了对logrus的依赖性:


 module github.com/rumyantseva/hello go 1.13 require github.com/sirupsen/logrus v1.4.2 // indirect 

go.sum文件也出现了,除了对logrus依赖项的哈希值之外,还存储了有关传递性依赖项哈希值的信息:


 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 

依赖代码本身在哪里? 可以在~/go/pkg/mod找到它。 另外,用于处理依赖项的校验和和其他开销信息也将存储在~/go/pkg


如果您已经使用过go get工具,您就会知道在提取依赖项时,它实际上会克隆存储库(例如,在git与git clone的情况下)。 但是go mod不能那样工作。 对于go mod代码go mod主要单位是模块。 模块是档案。 使用go mod依赖项时,它会通过GOPROXY显式地(如果您调用go mod download命令)或隐式地(如果您开始编译应用程序)来下载GOPROXY压缩档案。 让我们看看默认情况下如何在Go 1.13中设置代理:


 $ go env GOPROXY https://proxy.golang.org,direct 

因此,作为构建“ Hello,World!”的代理 由proxy.golang.org使用 。 当然,可以通过选择其他模块存储库来更改此变量。 例如,您可以部署自己的内部代理公司,该公司将存储,包括内部库,该库的代码未在开源中发布。


通常,如果我开始一个新项目并且不介意使用Go模块,那么我可能对GOPATH 。 Go会在需要时自行创建~/go目录。


什么时候需要GOPATH?


如果您基本上不使用Go模块(例如,在旧项目中),那么摆脱使用GOPATH更明确的工作可能并不那么简单。


要查看我的项目将会发生什么,如果我决定不使用go mod ,请删除文件~/hello/go.mod~/hello/go.sum 。 我还将删除~/go返回到开始时的系统状态:


 rm -rf ~/go ~/hello/go.mod ~/hello/go.sum 

只有main.go文件保留在~/hello main.go 。 如果我尝试使用go run来运行它会发生什么?


 $ go run main.go main.go:4:2: cannot find package "github.com/sirupsen/logrus" in any of: /usr/lib/go-1.13/src/github.com/sirupsen/logrus (from $GOROOT) /home/elena/go/src/github.com/sirupsen/logrus (from $GOPATH) 

在这里,这些可怕的GOROOTGOPATH :)


为了编译应用程序,我需要提取GOPATH的依赖GOPATH 。 我用旧的go get做到这一点:


 $ go get -v github.com/sirupsen/logrus github.com/sirupsen/logrus (download) created GOPATH=/home/elena/go; see 'go help gopath' get "golang.org/x/sys/unix": found meta tag get.metaImport{Prefix:"golang.org/x/sys", VCS:"git", RepoRoot:"https://go.googlesource.com/sys"} at //golang.org/x/sys/unix?go-get=1 get "golang.org/x/sys/unix": verifying non-authoritative meta tag golang.org/x/sys (download) golang.org/x/sys/unix github.com/sirupsen/logrus 

发生什么事了 首先, go get创建了~/go目录(指定为GOPATH )。 然后,开始克隆具有依赖性的存储库。 有趣的是,克隆存储库的速度明显慢于使用go mod下载和解压缩模块时的选项。 但是,依赖代码现在可以在~/go/src/


顺便说一句,在我干净的Ubuntu安装中仍然没有git客户端,为了go get工作,我必须安装它。


我启动该应用程序:


 $ go run main.go INFO[0000] Hello, world! 

有效!


那只是在应用程序级别,我现在不跟踪外部依赖项的版本。 如果由于漏洞而导致github.com/sirupsen/logrus存储库中的某个时刻不是我所期望的记录器,而是某些恶意代码,该怎么办? 迟早,我仍然需要使用工具来处理依赖关系,如果由于某些原因Go模块不适合,则必须寻找其他方法...


结论


本文未解决某些特定问题,并且在Go中使用外部依赖项仍然会引起很多问题。 但是,Go的新版本至少不对可以在何处创建项目的工作目录施加限制。


如果您要开始一个新项目,请尝试Go Modules! 仅当出现问题时,恢复使用依赖项的旧方法才有意义。 顺便说一句,如果您希望将所有依赖项存储在项目内部,则Go Modules支持供应商模式。


如果您需要使用现有项目,并且由于某种原因不想将其转换为Go Modules,则在项目文档中指出其部署和依赖管理的功能非常重要。 如果新来者不熟悉使用依赖项的旧方法,那么只要所有文档都到位,他们将更容易处理该项目。


顺便说一句,在10月7日举行的GolangConf会议上,作为一项特殊活动,我们正在计划建立一个专家区域,任何人都可以向会议计划委员会成员和俄罗斯Go社区爱好者提出有关Go的任何问题。 安装Go吗? 处理成瘾? 写微服务? 这是给我们的!

Source: https://habr.com/ru/post/zh-CN467697/


All Articles