Wire 是编译期依赖注入工具,通过生成硬编码初始化代码实现零反射开销、类型安全与调试友好;它要求导出函数参与构建,依赖自动递归解析,需用 go generate 触发代码生成。

Wire 是什么,为什么不用手写 NewXXX 函数
Wire 不是运行时反射注入库,它在编译前生成硬编码的初始化代码,所以没反射开销、类型安全、IDE 可跳转、调试友好。你写的是 inject.go 描述“要什么”,Wire 生成的是 inject_gen.go 实际“怎么 new”。一旦依赖链出错,报错在生成阶段,而不是运行时报 nil pointer dereference。
安装 Wire 并初始化项目结构
别用 go get 直接装全局命令——它会污染 GOPATH 或导致版本混乱。正确做法是作为开发依赖引入:
- 在项目根目录执行:
go install github.com/google/wire/cmd/wire@latest - 确保
$GOPATH/bin在$PATH中(macOS/Linux 检查echo $PATH,Windows 检查系统环境变量) - 运行
wire version验证是否可用;如果提示 command not found,说明路径没生效 - Wire 不要求特定目录结构,但约定把描述文件放在
cmd/yourapp/wire.go或internal/di/wire.go
写第一个 wire.Build 调用常踩的坑
最常见错误是 wire.Build 里漏传依赖构造函数,或传了没导出的函数(首字母小写),导致生成失败并报类似 no provider found for *db.DB 的错误。
- 所有参与构建的函数必须是导出的(首字母大写),比如
NewDB✅,newDB❌ -
wire.Build第一个参数是“目标函数”,比如InitializeApp;后面跟的全是它依赖的提供者(provider)函数 - 不要在
wire.Build里写逻辑,只列函数名;例如wire.Build(InitializeApp, NewDB, NewCache) - 如果某个 provider 需要参数,而这些参数本身也是依赖项,Wire 会自动递归解析——但前提是它们也在
wire.Build列表里,或被标记为wire.Value/wire.Struct
示例片段(非完整代码):
立即学习“go语言免费学习笔记(深入)”;
func InitializeApp(db *sql.DB, cache *redis.Client) *App {
return &App{db: db, cache: cache}
}
<p>func NewDB() (<em>sql.DB, error) { /</em> ... <em>/ }
func NewRedis() (</em>redis.Client, error) { /<em> ... </em>/ }</p><p>func init() {
wire.Build(InitializeApp, NewDB, NewRedis)
}生成代码后不生效?检查 go:generate 和构建流程
Wire 生成的 inject_gen.go 是普通 Go 文件,但很多人忘了把它纳入构建,或者误以为每次改了 wire.go 就自动更新。
- 推荐用
//go:generate wire注释 +go generate触发,而不是手动跑wire - 确保注释写在
wire.go文件顶部(且前面无空行),格式严格为://go:generate wire - 运行
go generate ./...后,检查是否生成了inject_gen.go;若没生成,大概率是wire.go里没写wire.Build,或函数签名返回类型不匹配 - 生成的文件必须和调用方在同一个包里;跨包使用需显式 import 并调用生成的函数,不能靠 Wire 自动跨包解析
容易被忽略的一点:Wire 不处理 interface 实现绑定,比如你有 type Cache interface{...} 和 type RedisCache struct{...},必须显式写个 provider 函数返回 Cache 类型,不能只注册 *RedisCache。










