GO基础总结
Go基础语法参考:https://www.cnblogs.com/vonlinee/p/19005628
环境搭建
# CentOS
yum install go
# Windows 直接官网下载二进制安装包即可
配置环境变量
# 指定Go的安装根目录
export GOROOT=/usr/local/go
# Go工作区目录(自定义,存放你的项目/依赖包,推荐默认)
export GOPATH=$HOME/go
# Goproxy镜像,解决下载依赖超时/失败,七牛云官方镜像
export GOPROXY= https://goproxy.cn ,direct
# 将GO可执行文件加入PATH中,使GO指令与我们编写的GO应用可以全局调用
$PATH=$PATH:$GOBIN:$GOROOT/bin
Windows 上修改GOPATH目录
GOPATH 是 go install 的默认目标目录,第三方依赖会下载到 pkg/mod 目录。建议将 GOPATH 以及相关的 GOCACHE 等目录迁移到非系统盘
go env -w GOPATH=D:\go-workspace
go env -w GOCACHE=D:\go-cache # 迁移编译缓存
通过 go version 查看安装的版本
➜ go version
go version go1.23.0 windows/amd64
环境变量
这三个是搭建 Go 开发环境最基本、必须了解的变量。
GOROOT
Go 语言安装的根目录。它指向 Go 的 SDK 所在位置,其中包含标准库、编译器、链接器等所有自带的工具。默认值:通常为 /usr/local/go(Unix-like)或 C:\Go(Windows)。现代版本的 Go 通常能自动设置,一般不需要手动修改。除非你安装了多个 Go 版本并需要切换。
GOPATH
在 Go Modules 出现之前,这是所有 Go 代码的工作目录。它有三个子目录:
- src(源代码)
- pkg(编译后的包文件)
- bin(编译后的可执行文件)。
自 Go 1.11 引入 Modules 后,GOPATH 的重要性已大大降低。但它仍然存在,主要用于存放通过 go install 安装的可执行工具(在 $GOPATH/bin 下)以及缓存旧版本(Go 1.4及之前)的包。默认值:$HOME/go(Unix-like)或 %USERPROFILE%\go(Windows)。
GOBIN
执行 go install 命令编译生成的可执行文件的存放目录。运行 go install 时,生成的可执行文件会放在此目录下。为了能在终端任何地方直接运行这些工具,强烈建议将 \(GOBIN 添加到你的系统 PATH 环境变量中。默认值:默认为 `\)GOPATH/bin 。你可以单独设置它,例如 export GOBIN=$HOME/.local/bin`。
命令行工具
go env
会列出所有与 Go 相关的环境变量及其当前值。Windows下输出内容类似于下面这样:
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\lenovo\AppData\Local\go-build
....
set GOENV=C:\Users\lenovo\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
查看特定的环境变量:go env VARNAME,在 Windows 的 Command Prompt 或 PowerShell 中,用法基本相同。只是变量名的大小写不敏感,但通常保持大写即可。
➜ go env GOPATH # 输出: /Users/username/go
➜ go env GOROOT # 输出: /usr/local/go
➜ go env GOPROXY # 输出: https://goproxy.cn ,direct
➜ go env GOPATH GOROOT GOOS GOARCH
C:\Users\lenovo\go
D:\Develop\Go
windows
amd64
使用 -json 标志可以以 JSON 格式输出所有环境变量
go env -json
# 获取特定变量的 JSON 值
go env -json GOROOT GOPROXY
常用环境变量的含义如下
| 变量名 | 含义 | 示例值 |
|---|---|---|
GOPATH |
工作区目录 | /Users/username/go |
GOROOT |
Go 语言安装目录 | /usr/local/go |
GOBIN |
可执行文件安装目录 | $GOPATH/bin |
GOOS |
目标操作系统 | darwin, linux, windows |
GOARCH |
目标架构 | amd64, arm64, 386 |
GOPROXY |
模块代理 | https://goproxy.cn ,direct |
GOMODCACHE |
模块缓存目录 | $GOPATH/pkg/mod |
CGO_ENABLED |
是否启用 CGO | 1 (启用) 或 0 (禁用) |
go build
要使用Go编译单个文件,直接在文件上运行 go build <文件名.go> 即可生成可执行文件(默认与源文件名相同),或者使用 go run <文件名.go> 直接编译并运行。若想指定输出文件名,可用 go build -o <输出名> <文件名.go>。
【go build】指令的作用是:在当前目录下编译生成可执行文件。注意,go build指令会调用所有引用包的源码,重新编译,而不是直接使用pkg里的编译后文件,如果在【\(GOROOT】与【\)GOPATH】下没有找到import引入包的项目源码,就会报错。
go run
go run 命令用于编译并直接运行源代码,它会在后台编译程序(生成临时可执行文件)然后立即执行,执行完毕后删除临时文件,非常适合快速测试和调试,而无需手动生成和管理可执行文件。它的基本语法是 go run [文件名.go] [参数...]。
go install
https://stackoverflow.com/questions/24069664/what-does-go-install-do
go install指令的作用是:编译源代码,如果为可执行文件(package "main"且包含main方法),则会编译生成可执行文件到 $GOPATH/bin目录下;源文件中 import 引入的其他包,就会被编译到$GOPATH/pkg/$GOOS_$GOARCH目录下。格式:go install 包名/包的地址
go install主要用于编译和安装可执行文件,核心目标是将代码编译成可执行文件(或库文件),并将编译产物安装到 Go 语言的标准目录中,方便后续直接调用。
- 先执行 go build 的编译逻辑,再把编译结果放到指定目录(区别于 go build 仅编译到当前目录)。
- 编译后生成可执行文件,安装到
$GOPATH/bin(或 $GOBIN)目录,可直接在终端运行。
go install 针对包而非单个文件,既可操作本地项目,也可操作远程第三方库,举个例子,在空目录下先初始化模块(Go 1.11+ 推荐),再安装:
go mod init hello
# 在$GOPATH/bin目录下生成hello可执行二进制文件
go install hello
go install / go build
go install也可以完成类似go build的功能,区别在于go install会生成二进制文件到 $GOPATH/pkg/$GOOS_$GOARCH目录下,但go install会把可执行文件自动生成到$GOBIN目录下,这是在一开始被配置到【$PATH】中了,这样就可以使项目可执行文件能被方便的全局调用。
用VSCode打开go代码时,vscode提供的go插件会去执行 go install -v golang.org/x/tools/gopls@latest这个命令,安装@latest版本的gopls这个包,gopls 是 go 官方提供的lsp服务,如果@latest这个版本的gopls和你装的go版本不兼容,则会去下载合适的go版本(估计下的这个版本只是gopls自身用的)
PS C:\Users\lenovo\go> go install -v golang.org/x/tools/gopls@latest
go: downloading golang.org/x/tools v0.41.0
go: downloading golang.org/x/tools/gopls v0.21.0
go: golang.org/x/tools/gopls@v0.21.0 requires go >= 1.25; switching to go1.25.5
go: downloading go1.25.5 (windows/amd64)
......
go get
参考:https://golang.org/doc/go-get-install-deprecation
使用 go get获取 Go 语言的包,go get主要下载依赖,go install主要用于编译和安装可执行文件.
go get 可以理解为git clone到 $GOPATH/src 目录后进行 go install
下载并安装包: go get <包的导入路径>,例如 go get github.com/gin-gonic/gin。
导入路径就是代码中写的import的内容,例如
import "github.com/gin-gonic/gin"
- 仅下载代码 (不安装):
go get -d <包的导入路径> - 更新包到最新版本:
go get -u <包的导入路径> - 同时下载测试所需的包:
go get -t <包的导入路径> - 下载指定版本的包,只需在包路径后添加 @ 符号和版本号,例如
go get <package_path>@<version>,即可下载该特定版本并更新 go.mod 文件,支持标签 (tag) 或提交哈希。
go get下载的包通常存放在 $GOPATH/pkg/mod目录中(Go Modules模式),如果是可执行文件则放在 $GOPATH/bin目录。具体路径可以通过运行 go env GOPATH命令查看,pkg/mod 缓存了所有依赖项,而 bin 存放编译好的二进制工具.
- 依赖包(Modules):
$GOPATH/pkg/mod,在这个目录下,Go按模块名称和版本号(如 github.com)存放下载的依赖库. - 可执行文件: $GOPATH/bin,使用 go install 或 go get(针对工具)安装的二进制程序会放在这里,并不是所有包都会有二进制程序
以 go get github.com/urfave/cli为例,它被下载到了 $GOPATH/pkg/mod 目录下:
$ go get github.com/urfave/cli
go: downloading github.com/urfave/cli v1.22.17
go: downloading github.com/cpuguy83/go-md2man/v2 v2.0.7
go: downloading github.com/russross/blackfriday/v2 v2.1.0
go: added github.com/cpuguy83/go-md2man/v2 v2.0.7
go: added github.com/russross/blackfriday/v2 v2.1.0
go: added github.com/urfave/cli v1.22.17
root@localhost ~/go/pkg/mod/github.com/urfave
drwxr-xr-x 1 root 197121 0 1月 14 22:58 'cli@v1.22.17'/
可以和Github上指定版本的release对比一下:https://github.com/urfave/cli/releases/tag/v1.22.17 ,发现基本上是一样的,估计就和我们直接通过 github 下载是一样的,下载到本地然后解压而已
依赖包的 go 版本和当前项目不一致
每个 Go Module 都可以在自己的 go.mod 中声明 go 版本,例如:
module github.com/example/lib
go 1.25.0
这个版本表示该模块要求的最低 Go 版本。当前项目也有自己的 go.mod:
module example.com/app
go 1.23.0
require github.com/example/lib v1.2.0
如果依赖包声明的 go 版本和当前项目不一致,要分情况看。
依赖包 go 版本低于或等于当前项目
例如当前项目是:
go 1.23.0
依赖包是:
go 1.20
这种情况通常没有问题。高版本 Go 可以编译低版本模块,只要依赖包本身没有其他兼容性问题即可。
依赖包 go 版本高于当前项目
例如当前项目是:
go 1.23.0
依赖包是:
go 1.25.0
Go 1.21 之后,主模块的 go 版本必须大于等于所有依赖模块的 go 版本。也就是说,当前项目 go 1.23.0 不能依赖一个要求 go 1.25.0 的模块。
执行 go get、go mod tidy、go build 时,可能会看到类似提示:
go: module github.com/example/lib@v1.2.0 requires go >= 1.25.0; switching to go1.25.5
go: upgraded go 1.23.0 => 1.25.0
如果 GOTOOLCHAIN=auto,Go 会尝试自动切换或下载满足要求的 toolchain,并可能自动把当前项目 go.mod 中的 go 行升级到依赖要求的最低版本。
升级后的 go.mod 可能变成:
module example.com/app
go 1.25.0
toolchain go1.25.5
require github.com/example/lib v1.2.0
如果不允许自动切换,例如设置了:
GOTOOLCHAIN=local
那么本机 Go 版本不满足要求时,就会直接报错,提示当前工具链版本太低。这时有三种处理方式:
- 升级本机 Go 版本,或者允许
GOTOOLCHAIN=auto自动下载工具链。 - 升级当前项目的
go版本,让它满足依赖包要求。 - 降级依赖包版本,选择一个
go.mod中go版本不高于当前项目的旧版本。
当前项目 go 版本是否一定要跟依赖完全一致
不需要完全一致,只需要满足“当前项目的 go 版本大于等于依赖要求的最低版本”即可。
例如:
// 当前项目
go 1.25.0
// 依赖 A
go 1.20
// 依赖 B
go 1.23
这是正常的。真正有问题的是反过来:
// 当前项目
go 1.23.0
// 依赖 B
go 1.25.0
这种情况下,依赖 B 可能使用了 Go 1.25 才支持的语法、标准库 API 或编译器行为,低版本工具链无法保证正确编译。
实际排查命令
查看当前项目声明的 Go 版本:
go list -m -f '{{.GoVersion}}'
查看某个依赖模块声明的 Go 版本:
go list -m -f '{{.Path}} {{.Version}} go{{.GoVersion}}' github.com/example/lib
查看所有依赖模块的 Go 版本:
go list -m -f '{{.Path}} {{.Version}} go{{.GoVersion}}' all
如果执行这些命令时触发了 toolchain 下载或 go.mod 变更,本质上就是 Go 在维护“主模块 Go 版本不能低于依赖模块 Go 版本”这个约束。
go clean
清理编译生成的临时文件、可执行文件(如 go build 生成的文件)
go doc
查看标准库 / 第三方包的文档(无需联网)
查看 Println 用法go doc fmt Println
[root@localhost bin]# go doc fmt Println
package fmt // import "fmt"
func Println(a ...interface{}) (n int, err error)
Println formats using the default formats for its operands and writes to
standard output. Spaces are always added between operands and a newline is
appended. It returns the number of bytes written and any write error
encountered.
包管理
最早的时候,Go所依赖的所有的第三方库都放在GOPATH这个目录下面
从v1.5开始开始引入vendor模式,如果项目目录下有vendor目录,那么go工具链会优先使用vendor内的包进行编译、测试等
从v1.11开始,引入了Go Module 作为依赖解决方案,到v1.14宣布Go Module已经可以用于生产环境,到v1.16版本开始Go Module默认开启
GOPATH 模式
GOPATH 模式是 Go 语言在 1.11 版本之前唯一的工作模式。该模式要求所有的 Go 代码(包括自己的项目和第三方依赖库)都必须放在一个单一的工作区目录下,这个目录就是 GOPATH。
它没有版本的概念,直接使用代码库的最新代码(默认是 master 分支或默认分支)。
约定有工作目录结构(需要自行创建), 在使用GOPATH的模式下,我们需要将应用代码存放在固定的\(GOPATH/src目录下,并且如果执行`go get`来拉取外部依赖会自动下载并安装到\)GOPATH目录下
- src ——存放源代码文件
- pkg——存放编译后的文件
- bin ——存放编译后的可执行文件*
多个项目最好都在一个 $GOPATH下,即 $GOPATH/src/项目1,$GOPATH/src/项目2
# Windows Terminal
cd "$(go env GOPATH)"
- bin:用来存放编译后的可执行文件
- pkg:用于存放编译后生成的归档文件
- src:用来存放go源码文件
第三方套件只要不是官方库,都需要放置在GOPATH/src的路径下才可以使用
当我们想用别人公开在GitHub上的套件,go get 可以帮我们从网络clone到GOPATH/src里面。虽然这样很方便,但是会发现GOPATH/src下会很复杂,除了有你自己开发的代码目录,同时也包含其他第三方库的专属目录
我们给不同的项目设置不同的GoPath,优点非常明显:
便于管理项目,每个项目都是不同的GoPath,这对于我们管理多个Golang项目而言,能够非常清晰的处理项目结构。如果我们把所有项目都放在同一个GoPath的src包下,那么项目的结构就会变得非常混乱,难以管理
但是当我们需要依赖第三方的包的时候,不同的项目设置不同的GoPath的缺点也非常明显:
第三方依赖的包和我们自己的Golang包混在一起,会给我们的项目文件管理带来一定的麻烦
不同的GoPath都需要下载依赖,那么磁盘中重复的依赖就会非常多,会占用我们大量的磁盘空间
GO MODULE
https://golang.org/ref/mod
在1.11开始推出了Go Modules的功能
环境变量 GO111MODULE
这是go使用到的一个环境变量,总共可以设置三种不同的值
- auto:默认值,go命令会根据当前目录来决定是否启用modules功能。需要满足两种情形:
该目录不在GOPATH/src/下,当前或上一层目录存在go.mod文件 - on:go命令会使用modules,而不会去GOPATH目录下查找。
- off:go命令将不会支持module功能,寻找依赖按照以前GOPATH的做法去寻找
目前1.16版本默认将这个参数设置成on,而且可能之后的版本会弃用掉GO111MODULE,因此建议要开发Go项目时就不再使用GOPATH了,而是采用Go Modules的做法,因此建议都设定为on
采用Go Modules,下载下来的第三方依赖就位于GOPATH/pkg/mod目录下
GO toolchain
Golang工具链:https://go.dev/doc/toolchain
toolchain 可以理解为 Go 编译运行程序时需要用到的一整套工具,包括标准库、编译器、汇编器、链接器以及 go 命令调用的其他工具。Go 1.21 开始,go 命令不仅能使用自己安装包里自带的 toolchain,还可以根据项目要求自动切换到其他 Go 版本,必要时还会自动下载对应版本。
例如本机安装的是 Go 1.23,但当前项目要求 Go 1.25,执行 go build、go test、go install 等命令时,Go 可能会输出类似下面的提示:
go: module example.com/app requires go >= 1.25; switching to go1.25.5
go: downloading go1.25.5 (windows/amd64)
这不是在全局替换你本机安装的 Go,而是当前这次命令选择了一个满足项目要求的工具链来执行。
go.mod 中的 go 和 toolchain
Go 项目可以在 go.mod 中声明两个和 toolchain 有关的字段:
module example.com/app
go 1.23.0
toolchain go1.25.5
它们的含义不一样:
go 1.23.0:项目最低要求的 Go 版本。低于这个版本的 Go 工具链不应该继续构建这个项目。toolchain go1.25.5:开发这个项目时推荐使用的 Go 工具链版本。如果当前go命令自带的版本低于它,就会尝试切换到这个版本。
如果 go.mod 中没有显式写 toolchain,可以理解为默认使用 go 行对应的工具链。例如:
go 1.23.0
大致等价于:
go 1.23.0
toolchain go1.23.0
所以:
go更偏向“最低兼容版本”。toolchain更偏向“当前开发推荐版本”。toolchain不能低于go指定的版本。
工具链选择规则
执行 go 命令时,工具链选择大致按下面的顺序:
- 先看
GOTOOLCHAIN环境变量。 - 再看当前工作区的
go.work,没有工作区就看当前模块的go.mod。 - 如果当前
go命令自带的版本已经满足go/toolchain要求,就直接用本地版本。 - 如果本地版本不满足要求,并且允许自动切换,就先在
PATH中查找类似go1.25.5的可执行文件。 - 如果
PATH中找不到,并且允许自动下载,就下载并缓存对应的 toolchain。
可以通过下面命令查看当前选择的工具链版本:
go version
查看 GOTOOLCHAIN 配置:
go env GOTOOLCHAIN
GOTOOLCHAIN
GOTOOLCHAIN 用来控制 go 命令如何选择工具链。Go 官方标准发行版默认是:
GOTOOLCHAIN=auto
常见取值如下:
| 值 | 含义 |
|---|---|
auto |
默认行为。先用本机 Go,如果项目要求更高版本,就自动切换或下载。 |
local |
只使用当前安装的 Go,不自动切换。如果项目要求更高版本,会直接报错。 |
path |
只在 PATH 中查找更高版本的 go1.x.x,不自动下载。 |
go1.25.5 |
强制使用指定版本的工具链。 |
go1.23.0+auto |
默认先按 Go 1.23.0 处理,但项目要求更高时仍允许自动切换。 |
临时指定:
GOTOOLCHAIN=local go test ./...
GOTOOLCHAIN=go1.25.5 go version
持久写入 Go 环境配置:
go env -w GOTOOLCHAIN=auto
go env -w GOTOOLCHAIN=local
如果写错了,想恢复默认配置,可以执行:
go env -u GOTOOLCHAIN
管理 go.mod 中的工具链版本
Go 1.21 之后,go 和 toolchain 也可以像普通依赖一样通过 go get 管理。
升级项目最低 Go 版本:
go get go@1.25.0
指定推荐工具链:
go get toolchain@go1.25.5
同时指定最低版本和推荐工具链:
go get go@1.23.0 toolchain@go1.25.5
删除 toolchain 行:
go get toolchain@none
需要注意的是,自动下载 toolchain 时,它本质上也是通过 Go 模块机制下载的特殊模块,会受到 GOPROXY 影响;但它不会写入 go.sum。如果把 GOSUMDB 设为 off,工具链下载可能会因为无法校验而失败。
go mod
Go 项目 必须开启 go mod (Go 1.16 及以上版本 默认开启 ,无需手动配置),如果是旧版本 Go,提前执行开启命令:
export GO111MODULE=on # Linux/Mac 临时开启,永久配置加进.zshrc/.bash_profile
set GO111MODULE=on # Windows cmd/PowerShell
下面来说明通过命令行创建一个项目的步骤
# 初始化 Go 模块(生成 go.mod 文件,标识项目依赖)
# go mod init <module name> <module name>可填可不填,不填的话预设就是默认的文件名称go.mod
go mod init hello
# 自动整理依赖(添加缺失的依赖、删除无用的依赖,更新 go.mod/go.sum)
go mod tidy
# 下载 go.mod 中声明的依赖到本地缓存
go mod download
# 将依赖复制到项目的 vendor 目录(离线开发用),打包依赖到本地
go mod vendor
在当前目录下创建一个 go.mod 文件
> go mod init hello
go: creating new go.mod: module hello
go: to add module requirements and sums:
go mod tidy
$ ll
total 1
-rw-r--r-- 1 lenovo 197121 24 1月 14 22:43 go.mod
创建源码文件 main.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
编译并运行:go run main.go
go.mod 文件
项目的「依赖清单」,纯文本文件,在项目根目录,由 go mod init 项目名初始化生成;
在此文件中可以写以下几个关键字:
- module:项目模块名
- go:定义go语言版本
- require:指定项目需要的所有依赖包+对应的版本号,预设是最新版,可以指定版本号
- exclude:排除该依赖和其版本
- replace:使用不同的依赖版本并替换原有的依赖版本注解,indirect代表被间接导入的依赖包
$ cat go.mod
module hello
go 1.23.0
require (
// indirect表示传递依赖
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/urfave/cli v1.22.17 // indirect
)
go.sum 文件
只要有开启go modules功能,go get 就不会像以前一样在GOPATH/src下放置依赖,而是会放在GOPATH/pkg/mod里面,并且go.mod会写好引入
项目的「依赖校验文件」,纯文本文件,自动生成,无需手动修改;里面记录了: 所有依赖包的版本哈希值(校验和) ;
作用:防篡改、验真伪 → 下次下载依赖时,Go 会对比下载包的哈希值和 go.sum记录的是否一致,一致才会使用,避免依赖包被恶意修改或下载到损坏的包;
go mod tidy会同步增删这个文件的校验记录,和 go.mod的依赖清单一一对应。
特别说明:
- 如果源文件里只import了内置包,没有第三方包,执行
go mod tidy是不会生成 go.sum 文件的 - 执行 go get 时也会更新 go.sum 文件
go.sum 使用场景
go.sum 不是锁版本文件,它不决定最终使用哪个依赖版本,真正决定依赖版本的是 go.mod 和最小版本选择规则(MVS)。go.sum 的职责是记录“某个模块版本对应的内容哈希”,保证同一个模块版本在任何机器上下载到的内容都是一致的。
典型使用场景有下面几类。
-
团队协作和 CI 构建
代码提交到 Git 后,
go.mod和go.sum应该一起提交。其他同事或 CI 服务器执行go test、go build、go mod download时,Go 会根据go.sum校验下载到的依赖包内容。如果哈希一致,就说明下载到的是同一份依赖。 -
依赖包被篡改
假设项目里已经记录了某个依赖的校验值:
github.com/example/lib v1.2.0 h1:abc123... github.com/example/lib v1.2.0/go.mod h1:def456...后来同一个版本
v1.2.0的源码被人改了,例如作者强推 tag、仓库被入侵、代理缓存被污染,或者公司内部镜像里同版本内容被替换。此时再次下载这个版本,Go 计算出来的哈希和go.sum记录的不一致,就会报错并拒绝使用这个依赖。类似错误如下:
verifying github.com/example/lib@v1.2.0: checksum mismatch downloaded: h1:xxxxxx... go.sum: h1:abc123... SECURITY ERROR This download does NOT match an earlier download recorded in go.sum.这就是
go.sum防止“依赖投毒”的核心价值:依赖名字和版本号没变,但内容变了,Go 可以识别出来。 -
防止代理或网络返回错误内容
Go 下载依赖时可能经过
GOPROXY,例如:go env GOPROXY # https://goproxy.cn ,direct如果代理服务返回了错误的 zip 包,或者网络中间层返回了损坏内容,
go.sum校验会失败。这样可以避免“下载成功但实际内容不对”的问题。 -
校验本地模块缓存
依赖下载后会缓存在
$GOPATH/pkg/mod。如果本地模块缓存被手动改过、磁盘损坏、杀毒软件误处理,也可能导致依赖内容和go.sum不一致。可以使用下面命令检查本地缓存是否和go.sum匹配:go mod verify正常输出:
all modules verified如果发现模块被修改,会提示对应模块校验失败。处理方式通常是清理模块缓存后重新下载:
go clean -modcache go mod download -
新机器首次下载依赖
如果本地没有某个依赖,Go 会先下载依赖,再校验它的哈希。如果
go.sum中已经有记录,就直接和本地记录比对;如果没有记录,Go 会查询 checksum database(默认是sum.golang.org)来确认这个模块版本的公开校验值,然后把结果写入go.sum。
go.sum 和 checksum database
go.sum 是项目本地保存的校验记录,checksum database 是 Go 官方提供的公共校验数据库,默认地址是:
sum.golang.org
两者配合使用:
go.sum已有记录:优先使用本地记录校验。go.sum没有记录:Go 会去 checksum database 查询这个模块版本的可信哈希。- 下载内容、
go.sum、checksum database 三者不一致时,Go 会拒绝使用该依赖。
如果是公司私有仓库,checksum database 查不到私有模块,需要配置 GOPRIVATE 或 GONOSUMDB 跳过公共校验库:
go env -w GOPRIVATE=gitlab.company.com/*
go env -w GONOSUMDB=gitlab.company.com/*
不建议随便设置:
GOSUMDB=off
因为这样会关闭公共模块的 checksum database 校验,依赖投毒风险会更高。只有在完全内网、无法访问公共校验库,并且有可信私有代理或私有校验机制时,才考虑关闭。
go.sum 里为什么有 /go.mod 记录
go.sum 中经常能看到两类记录:
github.com/example/lib v1.2.0 h1:xxxxxx...
github.com/example/lib v1.2.0/go.mod h1:yyyyyy...
第一行校验的是整个模块源码压缩包,第二行校验的是这个模块版本的 go.mod 文件。Go 有时候只需要读取依赖的 go.mod 来做版本选择,不一定需要下载整个源码包,所以会单独记录 /go.mod 的哈希。
简单记:
module version h1:...:校验依赖源码内容。module version/go.mod h1:...:校验依赖的模块声明文件。- 两者都很重要,不能手动乱删。
go mod tidy
自动同步项目的依赖关系,让 go.mod 和 go.sum 文件,与项目中 import 导入的包 保持绝对一致 。这包含两层意思:
1. 清理冗余依赖
2. 补齐缺失依赖
这个命令的执行逻辑就是「双向校验 + 自动修正」,执行时会 全盘扫描你的项目所有.go 源码文件 ,分析所有 import语句,然后执行:
自动下载【缺失】的依赖包
你的代码里 import了某个第三方包 / 自定义包,但 go.mod/go.sum 里没有记录这个依赖、本地也没有缓存 → go mod tidy 会自动从远程仓库(通过你的 GOPROXY配置)下载这个依赖,同时把依赖的 版本信息 、校验信息分别写入 go.mod 和 go.sum 文件,保证项目能正常编译运行。
你从 Git 拉取了一个别人的 Go 项目,执行 go run main.go提示 missing module xxx,执行 go mod tidy即可一键补齐所有缺失依赖。
自动删除【未使用】的冗余依赖
你的 go.mod/go.sum 里记录了某些依赖包,但你的项目源码中没有任何地方 import / 使用这些包 → go mod tidy 会自动把这些「无用依赖」从 go.mod(require 段)和 go.sum 中删除,同时清理本地缓存中对应的无用包。
场景举例:你开发时引入了 github.com/gin-gonic/gin,后来需求变更删掉了相关代码,此时 go.mod还残留这个依赖,执行命令即可一键清理。
依赖包的下载位置
go mod tidy下载的所有依赖包, 不会下载到你的项目目录里 ,而是统一缓存到 系统全局缓存目录 :
- Linux/Mac 系统:
$GOPATH/pkg/mod(默认GOPATH是~/go,完整路径~/go/pkg/mod) - Windows 系统:
%GOPATH%\pkg\mod
优点:所有 Go 项目共享一份依赖缓存,不会重复下载,节省磁盘空间;同一个依赖包同一个版本,本地只会存一份。
依赖包的版本选择
go mod tidy会遵循「 最小可用版本 」原则自动选择依赖版本:
- 优先匹配
go.mod中已声明的版本; - 如果未声明,会自动下载该依赖的 最新稳定版 ;
- 如果项目有版本兼容问题,你可以手动在
go.mod中指定版本,再执行go mod tidy即可生效。
其他相关环境变量
GOMODCACHE- 含义:Go Module 的缓存目录。所有下载的依赖包(包括特定版本)都会存储在这里。
- 默认值:
$GOPATH/pkg/mod。 - 用途:你可以通过设置此变量来改变依赖包的缓存位置,例如将其放在更大的硬盘分区上。
GOPROXY- 含义:Go Module 代理服务器的地址。用于加速依赖包的下载和提供稳定的可用性。
- 值:是一个逗号分隔的 URL 列表,也可以是特殊值
direct(直连代码仓库)或off(禁用网络)。 - 推荐设置:
https://goproxy.cn ,direct(适用于中国大陆,将goproxy.io或官方proxy.golang.org替换为国内镜像源以大幅提升下载速度)。 - 工作流程:Go 工具会按顺序尝试列表中的代理,直到成功为止。最后的
direct表示如果所有代理都失败,则直接尝试连接版本控制系统(如 GitHub)。
GOSUMDB- 含义:Go Checksum Database 的地址。用于验证下载的依赖包是否未被篡改,确保安全。
- 默认值:
sum.golang.org。 - 注意:访问此数据库可能较慢或不可用。如果你使用了可信的国内代理(如
goproxy.cn),通常会配备自己的校验数据库,通常不需要单独修改。在特殊内网环境下可设置为off来关闭校验(不推荐)。
GOPRIVATE/GONOPROXY/GONOSUMDB- 用于控制哪些私有模块(例如公司内部的 GitLab 仓库)不通过公共代理 (
GOPROXY) 下载,也不进行公共校验和校验 (GOSUMDB)。 - 值:逗号分隔的模块路径前缀 glob 模式列表(如
*.company.com,github.com/yourname/private-repo)。 GOPRIVATE设置了,就自动同时设置了GONOPROXY和GONOSUMDB。- 也可以单独精细控制
GONOPROXY和GONOSUMDB。
- 用于控制哪些私有模块(例如公司内部的 GitLab 仓库)不通过公共代理 (
下载包
默认情况下,go 命令可能会从 https://proxy.golang.org 下载模块。
它可以使用位于https://sum.golang.org的校验和数据库来验证模块。这两项服务均由谷歌的Go团队运营。
go 命令的下载行为可以通过 GOPROXY、GOSUMDB、GOPRIVATE 和其他环境变量进行配置。有关更多信息,请参阅“go help environment”和 https://golang.org/ref/mod#private-module-privacy 。
go vendor
go vendor 命令(通常指 go mod vendor 或第三方工具 govendor)是 Go 语言中管理项目依赖的机制,其核心是将项目所需的所有依赖包复制到项目根目录下的 vendor 文件夹中,以实现离线构建、版本锁定和保证构建一致性,其中 go mod vendor 是 Go 1.14+ 推荐的官方方式。
- go mod vendor: 创建或更新 vendor 目录,将 go.mod 中声明的依赖及其版本复制到 vendor。
go build -mod=vendor: 使用 vendor 目录中的依赖进行构建。
作用: 确保项目在任何环境都能使用指定版本的依赖,实现可重复构建。
这种模式下:包 github.com/$USER/$REPO会在本地目录 vendor/github.com/$USER/$REPO/目录下进行搜索
> go mod vendor
go: go.mod file not found in current directory or any parent directory; see 'go help modules'
注意:如果 vendor 的依赖列表和 go.mod 文件中的依赖列表不一致时
go: inconsistent vendoring in \the\path\to\project:
github.com/fatih/color@v1.18.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt
github.com/mattn/go-colorable@v0.1.13: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt
github.com/mattn/go-isatty@v0.0.20: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt
golang.org/x/sys@v0.25.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt
To ignore the vendor directory, use -mod=readonly or -mod=mod.
To sync the vendor directory, run:
go mod vendor
离线安装依赖
https://stackoverflow.com/questions/69603001/golang-offline-install-third-party-package
首先需要一台有网络的机器,以下面这个 go.mod 文件为例:
module hello
go 1.23.0
require github.com/urfave/cli/v3 v3.6.2 // indirect
执行 go mod vendor,将所有依赖项下载到项目目录下的 vendor/ 目录中。如下所示:/github.com/urfave/cli/v3 目录中包含了这个包的所有源码
└─vendor
└─github.com
└─urfave
└─cli
└─v3
......
└─module.txt
然后将 vendor 目录复制到没有网络的机器
如果内网环境,只有一台机器,只有包的 github 地址,如何进行包的安装?
GOPROXY 代理配置
GOPROXY 是一个以逗号分隔的 URL / 关键字列表,Go 工具链(go get/go mod)会按顺序尝试从列表中的地址拉取模块依赖。核心作用:
- 加速依赖下载(尤其国内访问海外仓库)。
- 解决网络限制导致的依赖拉取失败。
- 提供稳定、可缓存的模块镜像服务。用于内网或者公有镜像
设置 CDN 加速代理,以下是几个速度不错的提供者:
- 七牛:Goproxy 中国 https://goproxy.cn
- 阿里: mirrors.aliyun.com/goproxy/
- 官方: < 全球 CDN 加速 https://goproxy.io/>
- 其他:jfrog 维护 https://gocenter.io
在 Linux 或 macOS 上面,需要运行下面命令(或者,可以把以下命令写到 .bashrc 或 .bash_profile 文件中):
# 启用 Go Modules 功能
go env -w GO111MODULE=on
# 配置 GOPROXY 环境变量,以下三选一
# direct:直连模式,绕过代理,直接从 Git 等源码仓库拉取。
# 1. 七牛 CDN
go env -w GOPROXY= https://goproxy.cn ,direct
# 2. 阿里云
go env -w GOPROXY= https://mirrors.aliyun.com/goproxy/ ,direct
# 3. 官方
go env -w GOPROXY= https://goproxy.io ,direct
Windows 上配置:
# 启用 Go Modules 功能
$env:GO111MODULE="on"
# 配置 GOPROXY 环境变量,以下三选一
# 1. 七牛 CDN
$env:GOPROXY=" https://goproxy.cn ,direct"
# 2. 阿里云
$env:GOPROXY=" https://mirrors.aliyun.com/goproxy/ ,direct"
# 3. 官方
$env:GOPROXY=" https://goproxy.io ,direct"
通过 go env GOPROXY 验证是否设置成功
GONOSUMDB
GOPROXY 解决包的下载问题,如果是内网环境,即使通过GOPROXY配置了镜像,执行go get 命令仍然失败,类似下面的错误:
go: github.com/frankban/quicktest@v1.14.2: verifying module: github.com/frankban/quicktest@v1.14.2: Get "https://sum.golang.org/lookup/github.com/frankban/quicktest@v1.14.2": Connection Timeout
Go 为了保证模块下载的安全性,会从 GOSUMDB(默认是 sum.golang.org)获取每个模块的校验和(哈希值),并和本地下载的模块做比对。
set GOSUMDB=sum.golang.org
GONOSUMDB 用于指定不需要校验和验证的模块匹配规则;
核心作用:对私有仓库、内网模块或无法访问 GOSUMDB 的模块,跳过校验步骤,避免 go mod 操作时报错。
GONOSUMDB 的值是逗号分隔的模块路径匹配模式,支持两种写法:
- 精确匹配:如 github.com/your-company/private-repo;
- 通配符匹配:用 * 匹配任意前缀 / 后缀,如 .your-company.com(匹配所有内网域名下的模块)、github.com/your-company/(匹配公司名下所有仓库)。
跳过所有内网模块和公司私有仓库的校验
export GONOSUMDB="*.internal.com,github.com/your-team/*"
go env -W GOSUMDB=sum.golang.org
使用场景
- 私有模块:你的公司私有 Git 仓库(如 gitlab.your-company.com)的模块,不会被提交到公共的 GOSUMDB,如果不配置 GONOSUMDB,go mod 会因找不到校验和而报错;
- 内网模块:内网部署的模块仓库,无法被 sum.golang.org 抓取,自然没有校验和;
- 特殊代理场景:部分代理服务器未同步校验和,导致校验失败时,可临时跳过。
GONOSUMDB
不需要校验的包的白名单配置
go env -W GONOSUMDB=sum.golang.org
GOPRIVATE 私有模块
如果使用的 Go 版本 >=1.13, 可以通过设置 GOPRIVATE 环境变量来控制哪些私有仓库和依赖 (公司内部仓库) 不通过 proxy 来拉取,直接走本地:
# Go version >= 1.13
go env -w GOPROXY= https://goproxy.cn ,direct
# 设置不走 proxy 的私有仓库,多个用逗号相隔
go env -w GOPRIVATE=*.corp.example.com

浙公网安备 33010602011771号