go项目必须先goimports -w .再gofmt -w .,否则import分组混乱或格式不合规;internal/和pkg/有严格语义,禁止mvc式目录;接口应小而具体、定义在使用方;错误必须显式检查,panic仅用于致命错误。

Go 项目里不写 gofmt -w 和 goimports -w 就等于没开始编码——这不是风格偏好,是编译器和团队协作的硬性门槛。
gofmt 和 goimports 必须一起跑,顺序不能颠倒
只跑 gofmt -w 会留下混乱的 import 分组:标准库、第三方、本地包混在一起,golint 直接报错 import "fmt" should be grouped with other imports;只跑 goimports -w 又可能让缩进、括号位置、操作符空格不符合 Go 社区共识。
-
goimports本质是gofmt+ 导入管理,但它不保证格式细节(比如if x {是否换行) - 正确流程必须是:
goimports -w .→ 再gofmt -w .,或者直接用支持两者的编辑器插件(如 VS Code 的 Go 扩展默认启用) - CI 中应设为失败门禁,不是 warning;
make fmt脚本里这两条命令缺一不可
包名和目录结构别学 MVC,internal/ 和 pkg/ 有严格语义
建 controllers/、services/ 这类目录,本质是把框架概念强加给 Go——它既破坏包边界,又诱发循环依赖,还让测试 mock 成本陡增。
-
internal/下的包(如internal/user、internal/payment)禁止被外部模块导入,适合放业务核心逻辑和项目特有适配器 -
pkg/是显式设计为可复用的公共能力,比如pkg/metrics提供标准接口,别人能go get直接用;误把工具函数塞进pkg/common是高频陷阱 - 文件按主题拆,不是按 HTTP 方法拆:
internal/order/actions.go放createOrder()、cancelOrder()、refundOrder(),它们共享状态和错误传播逻辑
接口定义越小越好,别为了“统一”而抽象
Go 不需要 “Service 接口” 或 “Handler 接口” 这种大而全的抽象。真正需要多态的地方才定义接口,比如不同 DB 驱动共用 Queryer,而不是所有 handler 都塞进 Handler interface{ ServeHTTP() }。
-
http.Handler本身已足够;除非你要封装特定行为(如带 trace ID 的 wrapper),否则别另起MyHandler - 框架内部组件(配置加载、日志初始化)优先用函数或结构体字段组合,而非接口+实现——减少抽象层级就是降低理解成本
- 接口定义放在使用方包里,不在实现方;比如
user包需要调用支付能力,就由user定义PaymentClient接口,payment包去实现它
错误必须显式检查,panic 只用于程序无法继续的致命错误
框架层最容易犯的错,是把 “统一错误返回” 当成目标,结果用 panic 替代业务错误处理,或直接忽略 err。
- 任何可能失败的操作(DB 查询、配置解析、HTTP client 调用)都必须返回
error,且调用方用if err != nil显式检查 -
panic仅用于监听端口失败后退出、内存分配失败等程序无法继续的场景,绝不用于用户参数校验失败、库存不足等业务错误 - handler 函数签名推荐
func(w http.ResponseWriter, r *http.Request) error,便于中间件链式传递错误,比func(w http.ResponseWriter, r *http.Request)更安全
最常被忽略的其实是包注释和导入分组——internal/user 包没写完整句子开头的包注释,别人就无从判断它的职责边界;import 没分三组(标准库 / 第三方 / 本地),时间一长连自己都搞不清哪些依赖真被用了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











