Go Modules(Go Mod)、GOPATH简介

1 历史背景

1.1 GOPATH

    GOPATH指定外部Go语言代码开发工作区目录, 在 Go 1.5 版本之前,所有的依赖包都是存放在 GOPATH下,没有版本控制。这种方式的最大的弊端就是无法实现包的多版本控制,比如项目 A 和项目 B 依赖于不同版本的 package,如果 package 没有做到完全的向前兼容,可能会导致一些问题。从Go 1.8版本开始Go开发包在安装完成后会为GOPATH设置一个默认目录,并且在Go 1.14及之后的版本中启用了Go Module模式之后,不一定非要将代码写到GOPATH目录下,所以也就不需要我们再自己配置GOPATH了使用默认的即可

  在 Go 1.8 版本之前,GOPATH环境变量默认是空的。从 Go 1.8 版本开始,
Go 开发包在安装完成后会为 GOPATH设置一个默认目录。
  GOPATH在不同操作系统平台上的默认值
平台 	   GOPATH默认值      举例
Windows %USERPROFILE%/go 	C:\Users\用户名\go
Unix 	  $HOME/go 	        /home/用户名/go

  将 GOROOT下的bin目录及GOPATH下的bin目录都添加到环境变量中。



gopath模式下$GOPATH目录结构如下
-- bin 存放编译后生成的二进制可执行文件

-- pkg 存放编译后生成的 .a 文件

-- src 存放项目的源代码,可以是你自己写的代码,也可以是你 go get 下载的包

将你的包或者别人的包全部放在 $GOPATH/src 目录下进行管理的方式,我们称之为 GOPATH 模式。



  GOPATH 模式中 所有的依赖库会按路径存放在$GOPATH/src目录下,
编译时直接使用$GOPATH/src 目录下的代码,
go get 会下载代码到$GOPATH/src目录下。

1.2 go vender

    Go 1.5 版本推出了 vendor 机制,所谓 vendor 机制,就是每个项目的根目录下可以有一个 vendor 目录,里面存放了该项目的依赖的 package。go build 的时候会先去 vendor 目录查找依赖,如果没有找到会再去 GOPATH 目录下查找。

    Go 编译器会优先感知和使用 vendor 目录下缓存的第三方包版本,而不是 GOPATH 环境变量所配置的路径下的第三方包版本。这样,无论第三方依赖包如何变化,无论 GOPATH 环境变量所配置的路径下的第三方包是否存在、版本是什么,都不会影响到 Go 程序的构建。

    如果将 vendor 目录和项目源码一样提交到代码仓库,那么其他开发者下载你的项目后,就可以直接构建。因此,如果使用 vendor 机制管理第三方依赖包,最佳实践就是将 vendor 一并提交到代码仓库中。

    要想开启 vendor 机制,你的 Go 项目必须位于 GOPATH 环境变量配置的某个路径的 src 目录下面。如果不满足这一路径要求,那么 Go 编译器是不会理会 Go 项目目录下的 vendor 目录的。

    vendor 机制虽然一定程度解决了 Go 程序可重现构建的问题,但对开发者来说,它的体验却不那么好。一方面,Go 项目必须放在 GOPATH 环境变量配置的路径下,庞大的 vendor 目录需要提交到代码仓库,不仅占用代码仓库空间,减慢仓库下载和更新的速度,而且还会干扰代码评审,对实施代码统计等开发者效能工具也有比较大影响。另外,你还需要手工管理 vendor 下面的 Go 依赖包,包括项目依赖包的分析、版本的记录、依赖包获取和存放等等。

    Go 1.9 版本推出了实验性质的包管理工具 dep,这里把 dep 归结为 Golang 官方的包管理方式可能有一些不太准确。关于 dep 的争议颇多。

1.3 go mod

    Go 1.11 版本推出 modules,简称 mod,go mod的推出可以使我们更容易管理项目中所需要的模块。go mod 不再依靠 $GOPATH,使得它可以脱离 GOPATH 来创建项目。也就是你可以在你电脑的任意位置创建一个文件夹作为项目目录,然后使用 go mod 命令对目录进行初始化

2 Go Mod 模式

Go Modules 在 Go 1.11 和 Go 1.12 中有三个模式,根据环境变量 GO111MODULE进行配置:

  • 默认模式(未设置该环境变量或 GO111MODULE=auto)

Go 编译器在同时满足以下两个条件时使用 Go Mod

1.当前目录不在 GOPATH/src/ 下;
2.在当前目录或上层目录中存在 go.mod 文件;

  • GOPATH 模式(GO111MODULE=off)

Go 编译器从不使用 Go Mod。而会查找 vendor 目录和 GOPATH 以查找依赖项。

  • Go Modules 模式( GO111MODULE=on)

Go 编译器只使用 Go Mod,GOPATH不再作为导入目录,但它还是会把下载的依赖储存在 GOPATH/pkg/mod 中,也会把 go install 命令的结果放在 GOPATH/bin 中。

Go 1.13 及1.13以后版本默认使用 Go Mod 模式

3 Go proxy 设置

    在项目开发中我们可以会用到很多第三方库,由于有很多库在境外网站访问非常慢或需要翻墙,从而导致下载失败,在Go 1.13及以后版本我们可以通过设置环境变量GOPRIVATE来控制代理从而方便下载第三方库

# 设置GOPROXY代理
go env -w GOPROXY=https://goproxy.cn,direct 


https://goproxy.cn  为代理地址 

direct 为特殊指示符,用于指示 Go 回源到模块版本的源地址去抓取,
       也就是说在proxy找不到的时候,会直接访问模块源码所在的地址
       比如github


#设置GOPRIVATE来跳过私有库,比如常用的Gitlab或Gitee,中间使用逗号分隔:
go env -w GOPRIVATE=*.gitlab.com,*.gitee.com


常用代理

阿里云         https://mirrors.aliyun.com/goproxy/
nexus社区      https://gonexus.dev
七牛云         https://goproxy.cn
goproxy.io    https://goproxy.io

4 go mod 使用

4.1 设置项目目录

1. 在非$GOPATH目录的任意地方创建一个文件夹,然后再终端执行 go mod init project_name进行初始化操作,成功之后会发现目录下会生产一个go.mod文件

 2.查看go.mod内容,如下图

4.2 编写go程序添加依赖库

1.在demo01目录下创建 main.go文件,并引入gin库,启动一个web服务,代码如下

package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() //listen and serve on 0.0.0.0:8080
}

2.执行 go build main.go 命令会自动下载第三方包到默认的目录$GOPATH/pkg/mod

  如果遇到 main.go:4:2: no required module provides package github.com/gin-gonic/gin; to add it:
        go get github.com/gin-gonic/gin 错误,如下图 

我们可以根据提示手动进行以来下载

执行命令 go get -u -v github.com\gin-gonic\gin

-u  让命令利用网络来更新已有代码包及其依赖包。默认情况下,该命令只会从网络上下载本地不存在的代码包,而不会更新已有的代码包

-v  打印出用到的命令

 go: github.com/gin-gonic/gin@v1.7.7: verifying module: github.com/gin-gonic/gin@v1.7.7: Get "https://sum.golang.org/lookup/github.com/gin-gonic/gin@v1.7.7": dial tcp 172.217.163.49:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

执行命令后如果出现以上报错,可能是环境变量GOSUMDB导致,为了正常下载 我们可以临时关闭这个包安全性校验,执行以下命令

go env -w GOSUMDB=off

关闭后在此执行 go get可以正常下载

 下载完成后我们再次查看下go.mod这个文件,发现会自动添加上了依赖包

3. go.mod 提供了modulerequirereplaceexclude 四个命令

  • module 表示模块名称(路径)
  • require 依赖包列表及版本
  • replace 替换依赖项模块
  • exclude 忽略依赖项模块

上面截图中的 indirect 表示这个包是间接引用进来的

4.在我们下载依赖完成后会自动生成一个 go.sum 文件,这个文件主要是用来确保项目依赖的模块不会发生变化。内容如下图所示

go.sum 文件相比go.mod内容要多。每一行都是由 模块路径模块版本哈希检验值 组成,其中哈希检验值是用来保证当前缓存的模块不会被篡改。hash 是以h1:开头的字符串,表示生成checksum的算法是第一版的hash算法(sha256)

 go.mod 和 go.sum 是 go modules 版本管理的指导性文件,因此 go.mod 和 go.sum 文件都应该提交到你的 Git 仓库中去,避免其他人使用你写项目时,重新生成的go.mod 和 go.sum 与你开发的基准版本的不一致。

4.3 go mod 命令

  • go mod init : 初始化,生成go.mod文件,可加参数 项目名称
  • go mod download :手动触发下载依赖包到本地cache
  • go list -m -json all :以json的格式打印所有依赖详情
  • go mod graph :打印项目的模块依赖结构
  • go mod edit :编辑go.mod文件
  • go mod tidy :添加缺少的包,且删除无用的包
  • go mod verify:校验模块是否被篡改过
  • go mod why: 查看为什么需要依赖
  • go mod vendor:导出项目所有依赖到vendor下
  • 9
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
官方下载到的go module文档 Table of Contents The "Quick Start" and "New Concepts" sections are particularly important for someone who is starting to work with modules. The "How to..." sections cover more details on mechanics. The largest quantity of content on this page is in the FAQs answering more specific questions; it can be worthwhile to at least skim the FAQ one-liners listed here. Quick Start Example Daily Workflow New Concepts Modules go.mod Version Selection Semantic Import Versioning How to Use Modules How to Install and Activate Module Support How to Define a Module How to Upgrade and Downgrade Dependencies How to Prepare for a Release (All Versions) How to Prepare for a Release (v2 or Higher) Publishing a Release Migrating to Modules Additional Resources Changes Since the Initial Vgo Proposal GitHub Issues FAQs How are versions marked as incompatible? When do I get old behavior vs. new module-based behavior? Why does installing a tool via 'go get' fail with error 'cannot find main module'? How can I track tool dependencies for a module? What is the status of module support in IDEs, editors and standard tools like goimports, gorename, etc.? FAQs — Additional Control What community tooling exists for working with modules? When should I use the 'replace' directive? Can I work entirely outside of VCS on my local filesystem? How do I use vendoring with modules? Is vendoring going away? Are there "always on" module repositories and enterprise proxies? Can I control when go.mod gets updated and when the go tools use the network to satisfy dependencies? How do I use modules with CI systems such as Travis or CircleCI? How do I download modules needed to build specific packages or tests? FAQs — go.mod and go.sum Why does 'go mod tidy' record indirect and test dependencies in my 'go.mod'? Is 'go.sum' a lock file? Why does 'go.sum' include information for module versions I am no longer using? Should I still add a 'go.mod' file if I do not have any dependencies? Should I commit my 'go.sum' file as well as my 'go.mod' file? FAQs — Semantic Import Versioning Why must major version numbers appear in import paths? Why are major versions v0, v1 omitted from import paths? What are some implications of tagging my project with major version v0, v1, or making breaking changes with v2+? Can a module consume a package that has not opted in to modules? Can a module consume a v2+ package that has not opted into modules? What does '+incompatible' mean? How are v2+ modules treated in a build if modules support is not enabled? How does "minimal module compatibility" work in 1.9.7+, 1.10.3+, and 1.11? What happens if I create a go.mod but do not apply semver tags to my repository? Can a module depend on a different version of itself? FAQs — Multi-Module Repositories What are multi-module repositories? Should I have multiple modules in a single repository? Is it possible to add a module to a multi-module repository? Is it possible to remove a module from a multi-module repository? Can a module depend on an internal/ in another? Can an additional go.mod exclude unnecessary content? Do modules have the equivalent of a .gitignore file? FAQs — Minimal Version Selection Won't minimal version selection keep developers from getting important updates? FAQs — Possible Problems What are some general things I can spot check if I am seeing a problem? What can I check if I am not seeing the expected version of a dependency? Why am I getting an error 'cannot find module providing package foo'? Why does 'go mod init' give the error 'cannot determine module path for source directory'? I have a problem with a complex dependency that has not opted in to modules. Can I use information from its current dependency manager? How can I resolve "parsing go.mod: unexpected module path" and "error loading module requirements" errors caused by a mismatch between import paths vs. declared module identity? Why does 'go build' require gcc, and why are prebuilt packages such as net/http not used? Do modules work with relative imports like import "./subdir"? Some needed files may not be present in populated vendor directory

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值