莫得肉 發表於 2021-5-22 15:12:00

Go 语言中 GoPath 模式与 GoModules 模式介绍

<h2 id="gopath-模式">GoPath 模式</h2>
<p>当你在电脑上安装好 Go 后,在终端执行 <code>go env </code>命令,在输出的内容中,你会发现一个 <code>GOPATH</code> 的环境变量,它的值是一个目录路径。</p>
<p>从 Go 1.8 版本开始,安装 Go 开发包时会默认为 <code>GOPATH</code> 变量设置一个目录路径,它表示的是 Go 语言的工作目录,这个目录下会有三个子目录,它们分别是:</p>
<ul>
<li>
<p>bin:存放编译后生成的二进制可执行文件</p>
</li>
<li>
<p>pkg:存放编译后生成的 <code>.a</code>文件</p>
</li>
<li>
<p>src:存放项目的源代码,有自己写的代码,还有通过 <code>go get</code>命令下载的包</p>
</li>
</ul>
<p>注意当你第一次安装 Go 时,你的电脑上不一定存在 GOPATH 目录,你需要自己创建 GOPATH 的目录。</p>
<p>而所谓的『GoPath开发模式』就是指将项目文件和下载的包放到 <code>$GOPATH/src</code>目录下进行管理的方式。</p>
<h3 id="gopath-模式的弊端">GoPath 模式的弊端</h3>
<p>在 Go 1.11版本之前,开发者是必须要配置 这个<code>GOPATH</code>环境变量的,这种代码代码管理模式存在比较严重的问题就是没有版本控制。</p>
<p>因为多个项目都会放在<code>src</code>目录下,而每个项目依赖的一些第三方包也是下载在<code>src</code>目录下的,当升级某个依赖包时那就是全局升级了,引用这个依赖包的项目都跟着升级包版本了,这样是一件很危险的事,你不知道升级的包在另外一个项目中是否能正常运行的。而且当多人协同开发时,你不知道别人下载的包是不是你所用的那个版本,容易出错且不好排查原因。</p>
<h3 id="vendor-方案">vendor 方案</h3>
<p>其实针对 GOPATH 这种方式的弊端,官方也给出了解决方案,就是引入 vendor。解决的思路就是,在每个项目下都创建一个 vendor 目录,每个项目所需的依赖都只会下载到自己vendor目录下,项目之间的依赖包就互不影响了。在使用包时,会先从当前项目下的 vendor 目录查找,然后依次向上级目录查找。这种方式依旧是 GOPATH 模式下的,它解决了不同项目不能使用不同版本库的问题,但是也并不完美。如果多个项目使用的第三方库版本是一样的,那么就会造成相同的库存在多个目录下,占用空间而且没办法集中管理,再一个就是当你要分享自己的项目时,除了源码,还要上传所有依赖的包,才能保证别人使用时不会因为版本问题报错。</p>
<p>官方已经不推荐 GOPATH 的开发模式了,新版本中推荐使用 GoModules 模式,一起来看看。</p>
<h2 id="gomodules-模式">GoModules 模式</h2>
<p>GoModules 模式是 Go 语言 1.11 版本正式推出的,在 1.14 版本时,官方就发话 GoModules 的模拟已经成熟,可以用于生产环境了。所以新学习者们,可以直接用上这种模式了!</p>
<p>使用 GoModules 模式主要依赖于官方发布了自己的包管理工具,即 mod,如果做过前端的话,那你一定熟悉 npm,mod 就是类似于 npm 的工具。当你要使用 GoModules 模式时,你需要主动开启它,在终端输入命令 <code>go env</code> 时,你会发现一个 <code>GO111MODULE</code> 变量:</p>
<p><img src="https://img2020.cnblogs.com/blog/1151805/202105/1151805-20210521151849739-1345175338.png"></p>
<p>它就是开关,默认是 “auto” 模式,它所有可以设置的值有:</p>
<ol>
<li><strong>auto:</strong>自动模式,当项目下存在 go.mod 文件时,就启用 GoModules 模式;</li>
<li><strong>on:</strong>开启模块支持,编译时会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod下载依赖;</li>
<li><strong>off:</strong>关闭模块支持,使用 GOPATH 模式。</li>
</ol>
<p>所以当你要使用 GoModules 模式时,你需要执行开启命令:</p>
<pre><code>go env -w GO111MODULE=on
</code></pre>
<p>注意,如果上面这个命令执行后提示无权限修改系统环境变量时,你也可以在通过 <code>vim ~/.bash_profile</code> 的方式,在其中添加 <code>export GO111MODULE=on</code> 的方式修改,别忘了添加后要执行 <code>source ~/.bash_profile</code>。如果你电脑上终端用的是<code>zsh</code>,你还需要在 <code>~/.zshrc</code> 文件中添加 <code>source ~/.bash_profile</code>这一行。</p>
<p>然后 <code>go env</code> 查看一下是否开启成功:</p>
<p><img src="https://img2020.cnblogs.com/blog/1151805/202105/1151805-20210521152656497-1757393594.png"></p>
<p>当你开启 GoModules 模式时,你就无需将你的 go 项目放到 <code>$GOPATH/src</code> 目录下了,其实在新版 Go 的默认情况下,你就可以把项目随意放置了。接下来就看下怎么用 mod。</p>
<h3 id="使用-go-mod-初始化项目">使用 go mod 初始化项目</h3>
<p>go mod 的命令主要有:</p>
<pre><code>go mod download    // 下载依赖的module到本地cache(默认为$GOPATH/pkg/mod目录)
go mod edit      // 编辑go.mod文件
go mod graph       // 打印模块依赖图
go mod init      // 初始化当前文件夹, 创建go.mod文件
go mod tidy      // 增加缺少的module,删除无用的module
go mod vendor      // 将依赖复制到vendor下
go mod verify      // 校验依赖
go mod why         // 解释为什么需要依赖
</code></pre>
<p>我们主要使用 <code>go mod init</code> 来初始化项目,比如我们新建了一个项目目录 <code>go-demo</code>,那么就需要执行以下命令:</p>
<pre><code>// 需要进入到项目里面
cd go-demo
// 执行 init,init 后面的是自定义的当前项目的包名
go mod init goDemo
</code></pre>
<p>此时项目下就会多出一个 <code>go.mod</code> 文件,它的内容如下:</p>
<pre><code>module goDemo// 定义的包名

go 1.16// 当前使用的 go 版本
</code></pre>
<h3 id="下载第三方包">下载第三方包</h3>
<p>我们尝试下载一个第三方包,使用 <code>go get</code> 命令:</p>
<pre><code>go get github.com/jinzhu/now
</code></pre>
<p>注意:如果你下载错误或者缓慢,可能是因为没有设置 GOPROXY 代理,可以参考我的这篇记录:传送门</p>
<p>下载完成后,就会发现项目下多出一个 <code>go.sum</code> 文件,它的作用相当于锁定了当前项⽬依赖的所有模块版本,保证今后项目依赖的版本不会被篡改,更多的介绍可以自行搜索相关文档,一般我们不用管这个。</p>
<p>再看看 go.mod 文件中,多了一行 <code>require github.com/jinzhu/now v1.1.2 // indirect</code> ,这表示当前项目引入了这个包,其中注释 <code>// indirect</code> 表示的是间接的依赖,你可以理解为直接依赖的是 <code>jiinzhu</code>,间接依赖的是 <code>now</code>。</p>
<p>这里通过 <code>go get</code> 下载的包储是存在 <code>$GOPATH/pkg/mod</code> 目录下,同时会根据引入的路径来保存,比如上面下载的这个包,它的存放位置就是 <code>$GOPATH/pkg/mod/github.com/jinzhu</code>。注意 GOPATH 模式下,下载的包是存在 <code>$GOPATH/src</code> 目录下的。</p>
<h3 id="下载指定版本的第三方包">下载指定版本的第三方包</h3>
<p>在GoModules 模式下,你也可以下载指定版本的包,比如 <code>go get github.com/jinzhu/now@v1.1.0</code>,此时在 <code>$GOPATH</code> 的包目录下就存在两个版本的包文件:</p>
<p><img src="https://img2020.cnblogs.com/blog/1151805/202105/1151805-20210521173408738-968130640.png"></p>
<p>因为允许多版本包的存在,所以就不会出现只能用一个版本包的尴尬境地,也不用怕一个项目升级包版本而影响到另外一个项目。</p>
<p>无论你是升级版本还是降级版本,你都可以很方便地替换项目中引入的包版本,使用 <code>go mod edit -replace</code>:</p>
<pre><code>cd go-demo

go mod edit -replace=now@v1.1.2=now@v1.1.0 // 表示当引入 v.1.1.2 时其实找到的是 v.1.1.0
</code></pre>
<p>此时 <code>go.mod</code> 文件变成这样:</p>
<pre><code>module goDemo

go 1.16

require github.com/jinzhu/now v1.1.2 // indirect

replace now v1.1.2 =&gt; now v1.1.0 // replace 生效
</code></pre>
<h2 id="结尾">结尾</h2>
<p>关于 Go 语言开发的这两种模式,就介绍到这里了,更多细节要在实际开发中慢慢掌握,后续我可能会补充这部分内容,只是作为初学者,我觉得了解到这里就够了。</p>
<p>两种模式的简单总结:</p>
<ul>
<li>GOPATH 模式:项目文件夹和包文件都需要都放在 <code>$GOPATH/src</code> 目录下,不方便控制依赖包版本,一次包升级,所有依赖的项目都升级;</li>
<li>GoModules 模式:项目可以放在任意位置,新版本的 go 默认就可以把项目放在任意位置,通过 go mod 来管理依赖包,允许多个包版本存在,每个项目都维护自己的一份包版本,互不影响。</li>
</ul><br><br>
来源:https://www.cnblogs.com/wjaaron/p/14797003.html
頁: [1]
查看完整版本: Go 语言中 GoPath 模式与 GoModules 模式介绍