go build和go test强制要求规范目录结构:cmd/须按可执行名建子目录以控制二进制名并避免multiple main packages错误;internal/是编译器级私有边界;测试文件必须与源码同目录同包;go.mod必须位于模块根目录。

go build 和 go test 会直接拒绝不按约定组织的目录——这不是风格问题,是工具链报错。
cmd/ 下必须按可执行名建子目录,否则二进制名失控
Go 工具链通过 cmd/xxx 的目录名决定最终生成的可执行文件名,不是靠 main.go 内容推断。
比如 cmd/api/main.go 执行 go build cmd/api 输出 ./api;若写成 cmd/main.go,输出就是 ./cmd,完全偏离预期。
多个命令(CLI、Web、Worker)必须隔离在不同子目录:cmd/cli、cmd/server、cmd/worker。否则 go build ./cmd 会同时编译所有 main 包,触发 multiple main packages 错误。cmd/xxx/main.go 只做三件事:加载配置、初始化依赖、调用 app.Run();所有业务逻辑必须移出,不能塞任何非 main 包代码。
internal/ 是编译器级私有边界,不是“私有代码垃圾桶”
internal/ 不是约定,是 Go 编译器内置的导入限制机制:位于 github.com/user/project/internal/foo 的包,仅允许被 github.com/user/project/ 下的包导入;外部模块引用会直接报错 use of internal package not allowed。
适合放真正不该被复用的实现细节,例如 internal/tradebot/state(含私有状态机)、internal/dbmigration(仅本项目用的迁移逻辑)。
避免 internal/util/ 或 internal/common/ 这类命名——语义模糊,很快变成函数堆砌场,且违背“小而专注”的包设计原则。
如果某个包未来可能开源或跨项目复用,就别放 internal/,改放 pkg/ 或直接顶层路径(如 github.com/user/project/storage)。
测试文件必须与源码同目录同包,否则 go test 不识别
Go 不支持集中式 test/ 目录。运行 go test ./ 时,工具链只扫描当前模块下所有 *_test.go 文件,并要求它们与同目录的非 _test.go 文件属于同一 package,否则编译失败。
常见错误现象:internal/trade/accept.go(package trade)配了 internal/trade/accept_test.go(package main)→ 报错 cannot use ... in package main。
正确做法:测试文件和源文件必须声明相同包名,且放在同一目录下。
不要把测试文件挪到根目录或 test/ 子目录下——go test 根本不会看。
go.mod 必须在模块根目录,否则 import 路径全乱
go.mod 所在目录就是模块根,也是 import 路径的起点。很多人在子目录里乱跑 go mod init,结果导致 import 路径和实际目录不一致,IDE 找不到符号,go get 更新失败。
常见错误:在 src/github.com/user/project/cmd/api 下执行 go mod init api → 导入路径变成 api,但实际代码在 github.com/user/project/cmd/api 下,其他包无法正确引用。
正确做法:始终在项目最外层目录(即未来要被 import 的完整路径根)执行 go mod init github.com/user/project。main.go 可以放在根目录(单命令项目),也可以放在 cmd/xxx/(多命令项目),但绝不能放在 internal/ 或 pkg/ 下——它们是库路径,go build 不会识别。
internal/ 的限制是编译器硬规则,不是文档提醒;go test 对测试文件位置和包名的检查是即时且不可绕过的;go.mod 位置错了,整个项目的 import 体系就崩了——这些不是“可以试试看”的环节,是必须一步到位的工程前提。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











