go mod init 不下载依赖,因为它仅生成含 module 和 go 版本声明的 go.mod 文件,不触碰网络、不分析 import、不拉取任何代码;需后续执行 go mod tidy(补全并清理依赖)或 go build/go run(自动下载已 import 的依赖)。

go mod init 之后为什么没下载依赖
因为 go mod init 只生成 go.mod 文件,不触碰网络、不拉代码、不改任何已有文件。它只是声明“我是一个模块”,别的事一概不管。
常见误解是以为初始化就等于装好依赖——实际要等到你真正用到某个包(比如写了 import "github.com/gorilla/mux"),再执行 go build 或 go run main.go,Go 才会去下载并写入 go.mod 的 require 行。
- 如果项目里已有 import 但还没运行构建,
go mod init不会自动补依赖 - 想立刻拉取所有已声明依赖,用
go mod download - 想根据代码自动补全缺失依赖 + 清理多余项,用
go mod tidy
go get @ 后面该填什么版本标识
go get 的 @ 后不是随便写字符串,它必须能被 Go 解析为有效版本锚点,否则会报错 invalid version 或静默 fallback 到 latest。
合法格式只有三种:
-
@v1.2.3:精确 tag,要求远程仓库打了符合 SemVer 的 release 标签 -
@master或@main:分支名,Go 会转成伪版本(如v0.0.0-20240512103045-abcdef123456),注意这种版本无法被其他模块复现 -
@abc123:40 位或更短的 commit hash,同样转为伪版本,适合临时调试
不能写 @dev、@latest(虽然 go get -u 会隐式用 latest,但显式写无效)、也不能写带空格或特殊符号的路径。
go mod tidy 为什么删不掉某些 require 行
go mod tidy 只清理「代码里没 import,且没被其他依赖间接引用」的模块。它不是简单地按 import 删除,而是做完整的依赖图分析。
常见卡点:
- 某个包虽没直接 import,但被
go:generate注释或测试文件(*_test.go)引用了,它就会保留在require中 - 依赖 A 依赖 B,你删了 A 的 import,但 B 还被 C 依赖着,B 就不会被删
-
indirect标记的模块表示它是间接依赖,tidy不会主动删它,除非整个链都断了
想强制排除某个模块?只能手动从 go.mod 删除对应 require 行,再跑一次 go mod tidy —— 但得确认它真没被用到,否则编译失败。
replace 和 exclude 容易被忽略的副作用
replace 看似方便本地调试,但它会让整个模块树里的所有地方都重定向到你的本地路径,包括子依赖里声明的同一模块。
exclude 更危险:它只在当前模块生效,不影响子模块的依赖选择,可能导致不同模块加载同一依赖的不同版本,引发类型不匹配或方法缺失。
真实场景中:
- 用
replace调试私有库时,记得加// +build ignore或条件编译,避免提交到 CI -
exclude几乎不该手动写,除非你明确知道某个版本存在严重 bug 且无法升级,且已验证所有间接依赖都不受影响 - 两者都会让
go.sum记录变复杂,go mod verify失效范围扩大
最常被忽略的一点:这些指令只对当前模块生效,下游项目 go get 你时,不会继承你的 replace 或 exclude,除非他们也手动配——这恰恰是模块隔离的设计本意,也是容易踩坑的根源。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











