go子package命名和路径必须与文件系统严格一致,import路径即实际目录路径,internal/包仅限同module引用,pkg/存放可复用工具,根目录仅留main.go和初始化逻辑,go list -f '{{.importpath}}' ./...是验证包结构的唯一可靠方式。

子Package命名和路径必须与文件系统严格一致
Go 的 import 路径就是文件系统路径,go mod init example.com/foo 后,example.com/foo/bar 就必须对应 ./bar/ 目录,不能靠别名或重定向绕过。常见错误是手动改了 import 语句但没同步调整目录结构,导致 cannot find package 或构建时包被忽略。
- 每个子Package必须有独立目录,且目录名即其默认导入名(如
./internal/auth→"example.com/foo/internal/auth") -
internal/下的包只能被同 Module 的上层包引用,Go 编译器会强制检查,别指望用_或注释绕过 - 避免在子Package目录里放
main.go—— 除非你真要构建多个二进制,否则它会让go build ./...意外编译出一堆可执行文件
何时用 internal/,何时用 pkg/ 或根目录
不是所有逻辑都该拆成子Package。Go 社区默认分层其实是三层:顶层(API 入口)、internal/(实现细节)、pkg/(可复用的跨项目工具)。误把业务逻辑塞进 pkg/ 会导致耦合,误把工具函数全丢进 internal/ 又会让测试变困难。
-
internal/:数据库操作、中间件、领域模型实现 —— 外部不可 import,单元测试写在同目录下即可 -
pkg/:JWT 解析、HTTP 客户端封装、通用校验器 —— 需单独写go.mod并发布?不,先放这里,等稳定再抽成独立 Module - 根目录:只留
main.go和顶层Router/App初始化逻辑,别放业务 handler
go list -f '{{.ImportPath}}' ./... 是唯一可信的包视图
IDE 显示的“包结构”经常骗人,尤其当你用 VS Code + Go extension 时,它可能缓存旧 import 路径或误判 replace 规则。真正反映当前 Module 实际可见包的,只有 go list 输出。
- 运行
go list -f '{{.ImportPath}}' ./...查看所有可构建包,确认internal/下的没意外暴露 - 如果输出里出现
example.com/foo/internal/xxx,说明它被某个非同 Module 的地方 import 了 —— 这是编译错误,不是警告 - 搭配
go list -json ./...可查每个包的Imports字段,快速定位循环依赖(比如aimportb,b又 importa)
测试文件位置和 go test 范围控制很关键
子Package 的测试不是“放一起就行”。go test ./... 会跑所有包,包括 cmd/ 下的 main 包(如果它有 xxx_test.go),而 go test ./internal/... 又可能漏掉根目录的集成测试。更麻烦的是,某些测试依赖 internal/ 但本身放在根目录,结果 go test ./... 成功,go test ./internal/... 却失败。
立即学习“go语言免费学习笔记(深入)”;
- 每个子Package 的测试文件必须和源码同目录,用相同包名(
package auth),别建auth_test - 集成测试建议放
./test/目录,用//go:build integration标签隔离,运行时加-tags integration - CI 中优先用
go test ./... -race,而不是单个目录 —— Race Detector 对跨 Package 的 goroutine 交互最敏感
go build 前,都要问一句:这个 import 路径真的指向我预期的那个目录吗?go list 不撒谎,其它都是干扰。










