go mod init 仅创建 go.mod 文件,不生成目录或骨架代码;需手动构建标准分层结构:cmd/放主入口、internal/放私有逻辑、pkg/放可复用组件,确保可测试性与可维护性。

用 go mod init 初始化模块是起点,但不等于项目结构
很多人执行 go mod init myapp 后就以为项目建好了,其实这只创建了 go.mod 文件,没生成任何目录或骨架代码。Go 官方不内置项目脚手架,必须手动补全或借助工具。
常见错误是直接在根目录写 main.go 然后一路平铺,等加到 5 个包时才发现 import 路径混乱、测试难组织、构建产物污染源码。
- 推荐从一开始就按标准分层:比如
cmd/放主程序入口,internal/放私有逻辑,pkg/放可复用组件 -
cmd/myapp/main.go只负责解析 flag、初始化依赖、调用核心函数,业务逻辑全下沉 - 避免把所有东西塞进
main.go—— 这会让单元测试无法 import 主逻辑
手动创建最小可用结构(无外部依赖)
不需要装任何工具也能快速搭出可持续演进的结构。以下是最小但合理的布局:
myapp/
├── go.mod
├── cmd/
│ └── myapp/
│ └── main.go
├── internal/
│ └── app/
│ ├── app.go
│ └── app_test.go
└── pkg/
└── version/
└── version.go
关键点:
立即学习“go语言免费学习笔记(深入)”;
-
go mod init myapp必须在项目根目录运行,模块名建议用最终部署的域名路径(如github.com/user/myapp),方便后期发布到 GOPROXY -
cmd/myapp/main.go的import必须引用"myapp/internal/app",不能写相对路径 -
internal/下的包默认不可被外部 module import,适合放业务核心;pkg/则显式设计为可导出
用 curl + bash 一键生成结构(适合 CI 或批量初始化)
如果频繁新建项目,可以写个极简脚本避免重复劳动。下面这个命令能自动创建上述结构(Linux/macOS):
mkdir -p myapp/{cmd/myapp,internal/app,pkg/version} && \
cd myapp && \
go mod init myapp && \
touch cmd/myapp/main.go internal/app/app.go internal/app/app_test.go pkg/version/version.go
注意几个易错细节:
- 不要在
cmd/目录下执行go mod init,否则模块名会变成cmd/myapp,后续 import 全错 - 生成的
main.go需手动填入最简启动逻辑,例如:package main import ( "log" "myapp/internal/app" ) func main() { if err := app.Run(); err != nil { log.Fatal(err) } } - 如果用 VS Code,记得在打开项目前先
cd myapp,否则 Go 扩展可能识别不到 module 根
为什么不用 go-kit 或 kratos 这类框架?
它们确实带完整目录和模板,但代价是强约束和隐式约定。比如 kratos new myapp 会强制你接受 protobuf + gRPC + config center 三层结构,哪怕你只是写个 CLI 工具。
真正需要警惕的是“过早抽象”:一个只有 3 个 HTTP handler 的服务,没必要一上来就拆 data/、biz/、service/ 三层。先跑通 cmd → internal → pkg 三级就足够清晰。
复杂点往往不在结构本身,而在于什么时候该把 internal/app 拆成 internal/handler 和 internal/service —— 这取决于接口变更频率和测试隔离需求,不是靠模板能预判的。










