【Go】Go Modules详解

介绍

Go Modules是Golang官方推荐的依赖管理(dependency management)解决方案。

在Go v1.11/1.12版本引入,在Go 1.13版本稳定并默认打开。

官方文档:https://go.dev/blog/using-go-modules

Package和Module的区别

在Go里面Package是一个目录下面代码的一个集合,也是go语言程序的组成单位。

不同的Package之间可以相互调用。

每个.go文件只能属于一个Package,并且要在文件最开头声明该.go文件属于哪一个Package

Package下的.go文件名可以与包名相同。

每个Package还有默认的init方法,在import进来时就会去执行,而且允许每个文件中都有init()这个方法,在import时自然是每个文件里的init()都会执行。

Module则是一个目录下所有Package的集合。

如何开启Go Modules

使用go env命令可以查看你的Go Modules是否开启。

我是Go v1.16,Go Modules默认开启

syb@ZIBESUN-MB0 package_test % go env
GO111MODULE="on"     # Go Modules已开启
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/syb/Library/Caches/go-build"
GOENV="/Users/syb/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/syb/go/pkg/mod"
GONOPROXY="github.com/ZibeSun/PDT-serve"
GONOSUMDB="github.com/ZibeSun/PDT-serve"
GOOS="darwin"
GOPATH="/Users/syb/go"
GOPRIVATE="github.com/ZibeSun/PDT-serve"
GOPROXY="https://goproxy.cn"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.16.6"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/syb/go/src/package_test/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/mr/858gxxx104d1dddvm7dx8nf80000gn/T/go-build932787381=/tmp/go-build -gno-record-gcc-switches -fno-common"

如果你的Go版本较老(v1.13以前),默认不开启Go Modules的话,该如何开启Go Modules呢?

go env -w GO111MODULE=on
# 打开Go Modules开关

GO111MODULE一共有三个值可选:

  • on:开启Go Modules,编译时会从GOPATHvendor文件夹中查找包。
  • off:关闭Go Modules,编译时会忽略GOPATHvendor文件夹,只根据 go.mod下载依赖。
  • auto:当项目在$GOPATH/src外且项目根目录有go.mod文件时,自动开启模块支持。

如何初始化Go Modules

go mod init [MODULE_PATH]
# 初始化Go Modules,它将会生成go.mod文件。
# [MODULE_PATH]填写的是模块引入路径,你可以根据自己的情况修改路径

如果你在Goland中创建一个Go项目,那么Goland会帮你自动初始化Go Modules。

基础使用命令

go get [MODULE_PATH]
# 拉取指定的依赖库到本地并将它们添加到go.mod中
# 可以指定版本号,如 go get roc.io/quote@v1.5.2
-u # 强制使用网络去更新包和它的依赖包

go get -u
# 更新现有的依赖

go mod tidy
# 整理现有依赖
# 扫描当前项目的源文件,拉取源码需要的依赖库并将它们添加到go.mod中,从go.mod中移除源码中不需要的依赖库

go mod download
# 下载go.mod文件中指明的所有依赖

go mod edit
# 编辑go.mod文件
go mod edit -replace=golang.org/x/time@v0.0.0-20220224211638-0e9765cccd65=github.com/golang/time@v0.0.0-20220224211638-0e9765cccd65
# 将golang.org/x/time包替换为github.com/golang/time
# 会在go.mod文件中replace下新增替换信息

go mod graph
# 查看现有的依赖结构

go mod verify
# 校验模块是否被篡改过

go list -m all
# 列出当前模块及其所有依赖项

go.mod文件

我们初始化Go Modules后,go.mod文件生成。

go.mod的内容比较容易理解,通常具有以下结构:

  • 1、本模块的引用路径
  • 2、项目使用的go版本
  • 3、项目所需的直接依赖包及其版本

而在实际应用中,你可能会见到更复杂的go.mod文件,比如:

module package_test

go 1.16

require (
	github.com/unknwon/com v1.0.1 // indirect
	golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)

exclude github.com/unknwon/com v1.0.0

replace (
	golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 => github.com/golang/time v0.0.0-20220224211638-0e9765cccd65
	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 => github.com/golang/xerrors v0.0.0-20200804184101-5ec99f83aff1
)

这个go.mod文件多出了两个内容:

  • exclude:忽略指定版本的依赖包
  • replace:在国内不通过科学上网的情况下,一些包如golang.org/x的各个包可能难以拉取,于是你可以通过go mod edit -replace命令将其替换成github上对应的库。

go.sum文件

当我们开始拉取一些库后,go.sum文件生成。

go.sum文件相比于go.mod文件,内容就比较多了,密密麻麻的一片。

go.sum里的每一行都是由**[模块路径],[模块版本],[哈希校验值]**组成,其中的哈希校验值是用来保证当前缓存的模块不会被篡改。哈希校验值都是以h1打头的,h1表示生成该校验值的算法是第一版的hash算法,即sha256

go.sum文件例子:

github.com/golang/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
github.com/golang/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

值得注意的是,有的包在go.sum里只有一行:

<module> <version>/go.mod <hash>

而有的包却有两行呢:

<module> <version> <hash>
<module> <version>/go.mod <hash>

正常情况下,每个依赖包版本会包含两条记录,第一条记录为该依赖包版本整体(所有文件)的哈希值,第二条记录仅表示该依赖包版本go.mod文件的哈希值,如果该依赖包版本没有go.mod文件,则只有第一条记录。

本文参考文章

一文搞懂 Go Modules 前世今生及入门使用-【写代码的明哥】

干货满满的 Go Modules 和 goproxy.cn-【煎鱼】

【Go专家编程】一文搞懂go.sum工作机制

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值