模块初始化必须显式指定module path,否则依赖目录名推断易致import失败或协作混乱;应使用真实托管地址如github.com/yourname/myproject,避免后续重写import语句。

模块初始化必须显式指定 module path
不写路径或依赖目录名推断,大概率导致后续 import 失败或协作混乱。go mod init 不是“随便起个名字就行”,它直接决定别人怎么导入你的包。
- 正确做法:用真实托管地址,比如项目在 GitHub,就执行
go mod init github.com/yourname/myproject - 错误现象:
import "myapp"在他人机器上会报cannot find module providing package myapp - 本地练习时也建议用类似
example.com/myproject这种格式,避免将来迁移时重写所有 import 语句 - 模块路径一旦写进
go.mod,就别轻易改——否则已发布的版本、下游依赖的 import 路径全失效
init 函数不是初始化逻辑的合理出口
把数据库连接、配置加载、全局状态设置塞进 init(),看似省事,实则埋雷。它的执行时机不可控,且无法返回 error。
- 常见错误:在
init()里调用sql.Open或读取config.yaml,失败时只能panic,无法优雅降级或提示具体原因 - 推荐替代:定义一个
Setup()或NewApp()函数,显式调用并检查返回的error - 多个包之间依赖
init()执行顺序?别依赖——Go 只保证包级init()在main()前执行,但顺序由文件名字典序决定,极易出错 - 真正适合
init()的场景极少:比如注册 encoder、预热 sync.Pool、设置 global flag 默认值
配置与依赖应在 main 入口或 App 初始化时集中处理
模块本身不该“自己启动自己”。一个可复用的 Go 模块(比如 github.com/yourname/auth)不应该在 init 阶段连 Redis;它该提供 NewAuthenticator(...),由使用者决定何时、如何初始化。
- 反模式示例:模块里
init()直接调用redis.Dial(...),导致单元测试无法 mock,也无法支持多套环境配置 - 正向设计:暴露构造函数,接受依赖作为参数(dependency injection),例如
NewService(redisClient *redis.Client, cfg Config) - 如果确实需要“开箱即用”的初始化封装,用
MustNewXXX()函数,内部 panic 错误(仅限启动阶段),但必须和普通NewXXX()并存,留给测试和高级用例空间 - 注意:
go build会编译所有init(),哪怕你只 import 了模块里的一个工具函数——这可能导致无意义的副作用
go.mod 生成后别忽略 go.sum 和 Git 协同
go mod init 只是起点,没提交 go.sum 或没配 Git 标签,等于没完成初始化。
立即学习“go语言免费学习笔记(深入)”;
- 首次运行
go mod init后,立刻执行go mod tidy,确保go.sum生成并记录校验和 - 务必把
go.mod和go.sum一起git add并提交——这是让协作者构建结果一致的最小必要条件 - 如果已有 Git tag(如
v1.2.0),后续go get github.com/yourname/myproject@v1.2.0才能精准拉取,否则可能 fallback 到 pseudo-version - 别手动编辑
go.mod:增删依赖一律用go get或go mod tidy,否则容易破坏语义版本解析逻辑


















