
Go mod init 之后为什么 go run 报错找不到包?
根本原因不是模板没写对,而是当前目录没被 Go 视为 module 根——go.mod 里声明的 module 名和实际 import 路径不一致。
常见错误现象:go run main.go 提示 cannot find package "xxx" in any of...,尤其在子目录里执行时。
- 确保
go mod init在项目根目录运行,且 module 名用的是你未来要发布的路径(比如github.com/yourname/project),别用./或本地相对路径 - 所有
import语句必须以该 module 名开头,例如import "github.com/yourname/project/internal/handler",不能写成import "./internal/handler" - 如果只是本地开发、不发布,module 名可以是任意合法字符串(如
myapp),但一旦写了,所有内部 import 就得严格匹配,否则go build和go test都会失败
脚手架里要不要预置 internal/ 和 cmd/ 目录?
要,而且这是 Go 工程规范里最值得立刻落地的一环——它直接决定后续是否能安全拆包、复用、隔离实现细节。
使用场景:多人协作、后期要抽离库、需要区分可执行入口和核心逻辑。
立即学习“go语言免费学习笔记(深入)”;
-
cmd/下放main.go,只负责初始化、参数解析、启动服务,一行业务逻辑都不写 -
internal/放所有不对外暴露的代码(如 handler、service、repo),Go 会阻止外部 module import 它们 - 别把配置文件或 migration 脚本硬塞进
internal/;它们属于“资源”,更适合放在configs/或migrations/根目录下,用embed.FS加载
go mod tidy 总是拉取 dev 分支或旧 tag?
因为依赖项的 go.mod 文件里锁定了特定 commit 或分支,而 go mod tidy 默认尊重上游声明,不是按你本地 go.sum 或 go list -m all 显示的版本来。
性能影响:频繁拉取非 release 版本会导致构建变慢、CI 不稳定;兼容性风险:dev 分支 API 可能随时破坏。
- 检查
go.sum中对应模块行末尾是不是// indirect,如果是,说明它不是你直接 require 的,而是某依赖带进来的——这时得去查那个依赖的go.mod - 用
go get example.com/pkg@v1.2.3显式升级到稳定 tag,再go mod tidy,Go 会自动替换间接依赖 - 想彻底屏蔽某模块的 dev 引用?在
go.mod末尾加replace example.com/pkg => example.com/pkg v1.2.3,但仅限调试,别提交到主干
模板里该不该内置 Makefile 或 air 热重载?
该,但只作为可选开关,而不是默认开启——热重载在 CI、容器环境里毫无意义,反而增加理解成本和误用风险。
容易踩的坑:开发者习惯性改了 main.go 就等 air 自动重启,结果忘了加 go:generate 注释或没跑 mockgen,导致运行时 panic。
- Makefile 推荐只保留四条命令:
make build(go build -o bin/app ./cmd/app)、make run(go run ./cmd/app)、make test(go test ./...)、make fmt(gofmt -w+goimports -w) - 如果加
air,配置文件.air.toml必须排除**/testdata/**和**/mocks/**,否则文件变动触发无限重启 - 所有自动化工具的安装说明写在
README.md里,别塞进脚本——不同人用 macOS/Linux/WSL,brew install和apt-get路径差异太大
最常被忽略的其实是 go.mod 文件本身的版本语义:哪怕只是内部项目,也建议从 v0.1.0 开始打 tag,而不是长期停留在 require xxx v0.0.0-20240501123456-abcdef123456 这种 pseudo-version。后者看着精确,实则让依赖关系变成黑盒,排查问题时连“这个版本到底有没有包含某次 fix”都难确认。










