cmd/子目录名必须等于二进制名,internal/是编译器级私有边界,测试文件须与源码同目录同包;main.go仅解析flag、加载配置、调用app.run(),业务逻辑须移出。

cmd/ 下每个子目录名必须等于最终二进制名
Go 工具链不认 main.go 里的注释或变量名,只看路径:运行 go build ./cmd/myapp,输出就是 ./myapp;如果写成 ./cmd/main.go,输出会是 ./cmd,和预期不符。
多个命令共存时(比如 CLI + worker + migrator),必须分目录:cmd/cli、cmd/worker、cmd/migrate。否则 go build ./cmd 会报 multiple main packages 错误。
-
main.go只做三件事:解析 flag、加载配置、调用app.Run()—— 所有业务逻辑必须移出 - 别在
cmd/下放任何非package main的代码,否则go list ./会误判包路径 - 如果将来要支持交叉编译或容器多阶段构建,每个
cmd/xxx应能独立go build
internal/ 是编译器级私有边界,不是代码垃圾桶
Go 编译器硬性限制:github.com/user/project/internal/foo 只能被 github.com/user/project/ 下的包导入,外部模块引用直接报错 use of internal package not allowed。
但它不是“内部代码随便塞”的理由。常见错误是建一堆泛用目录,比如 internal/util 或 internal/common,结果演变成函数堆砌场,语义全失。
- 按职责而非“内部感”建子目录:比如
internal/auth、internal/payment、internal/dbmigration - 若某包未来可能开源复用,就别放
internal/,改放pkg/或顶层(如github.com/user/project/storage) - 禁止
pkg/xxx直接 importinternal/yyy—— 这说明接口抽象漏了,该把接口提到pkg/,实现留在internal/
测试文件必须和源码同目录、同包、_test.go 后缀
Go 没有集中式 test/ 目录概念。go test ./ 只扫描当前模块下所有 *_test.go 文件,并要求它们与同目录的非 _test.go 文件属于同一 package,否则编译失败。
在 Golang 中使用 samber/hot 进行内存缓存,支持 LRU、LFU、TinyLFU、W‑TinyLFU、S3FIFO、ARC、TwoQueue、SIEVE、FIFO 等淘汰算法,提供 TTL、缓存加载器及分片功能。
比如 internal/user/user.go(package user)的测试,必须是 internal/user/user_test.go(同样 package user)。想测未导出函数?只能同包;想黑盒测导出接口?可用 package user_test,但此时访问不了私有字段。
- 别把测试文件扔到项目根目录下的
test/或tests/——go test根本不会发现它们 - 集成测试或端到端测试可放
test/integration,但那是辅助脚本驱动的,不走go test自动发现流程 - 每个
_test.go文件应专注验证一个源文件,避免跨包混合测试
pkg/ 不是“工具包默认收纳区”,而是对外承诺的契约
pkg/ 下的代码会被其他项目直接 import,所以它不是“先放着再说”的中转站,而是有明确契约责任的对外接口层。
常见翻车点:早期把 pkg/config 当通用配置库,结果里面硬编码了 Kubernetes ConfigMap 路径,导致 CLI 工具无法复用;或者 pkg/utils 里混入了 HTTP 客户端逻辑,破坏了无依赖原则。
- 推迟提取:先写死在
internal/,等同一逻辑被第二个服务/命令复用时,再拆——接口放pkg/,实现按场景分到internal/xxx/k8s和internal/xxx/file - 每个
pkg/xxx子目录必须附带约束文档,比如//go:generate注释注明:“仅允许依赖context.Context和标准库,禁止 import 任何internal/” - 如果某个包连自己项目里都只被一处使用,就别放
pkg/—— 它大概率还没准备好对外暴露
最常被忽略的一点是:目录结构不是一次性设计完就一劳永逸的。随着命令增多、复用逻辑浮现、测试类型分化,cmd/、internal/、pkg/ 的边界会自然移动。关键是每次移动都得有明确动因,而不是因为“别人这么写”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










