Wire 是编译期依赖注入工具,仅生成初始化代码;需用 //+build wireinject 注释标记文件,provider 函数签名须严格匹配依赖类型,支持 error 自动传播,推荐用 NewSet 拆分模块并避免跨包引用。

wire 不是用来“运行时管理依赖”的容器,它只在构建前生成纯 Go 初始化代码。如果你的项目已有清晰的构造函数(NewXxx)、接口抽象和分层结构,wire 就能自动拼出完整的初始化链;否则它只会报错、拒绝生成。
wire.go 文件必须加 //+build wireinject 注释
不加这行注释,go build 会直接忽略该文件,wire 命令也找不到 injector 函数。
-
wire命令只扫描带//+build wireinject标签的.go文件 - 该文件必须和目标 injector 函数在同一包内
- 文件里不能有其他非 wire 相关逻辑(比如实际业务代码、测试用例),否则可能干扰分析或触发误报
常见错误现象:
-
go run github.com/google/wire/cmd/wire报no main found:其实是没找到带//+build wireinject的文件 -
could not find provider for <em>http.Server</em>:provider 函数不在当前包,或返回类型是http.Server而不是http.Server
provider 函数签名必须严格匹配依赖需求
wire 只看函数签名,不读函数体。参数顺序无关,但每个参数类型必须能被“解出来”——要么是基础类型(string、int),要么有对应 provider,要么是标准库已知类型(如 *log.Logger)。
-
<em>sql.DB</em>和database/sql.DB视为不同类型,不能混用 - 接口类型(如
io.Reader)必须由唯一 concrete type 提供;若两个 provider 都返回io.Reader,wire会报multiple providers - 带
error返回的 provider(如func() (*sql.DB, error))会被自动处理:任一环节出错,整个初始化函数返回error
示例中易错写法:
-
func ProvideDB(cfg Config) database/sql.<em>DB</em>→ 错,应返回sql.DB -
func NewHandler(s Service) *Handler→ 若Service是接口,必须确保只有一个 provider 返回该接口实现
用 wire.NewSet 拆分和复用依赖模块
大型项目不应把所有 ProvideXxx 和 NewXxx 全塞进一个 wire.Build() 调用里。按关注点分组(如 StorageSet、HTTPSet、TestSet),既利于协作,也方便测试环境替换。
-
wire.NewSet(ProvideDB, NewRepository, NewCache)可被多个 injector 复用 - 测试时可定义
MockSet = wire.NewSet(ProvideMockDB, NewMockRepository),在InitializeAppForTest中替换原 set - 注意:set 之间不能循环引用;
wire不检查跨包 set 的完整性,只校验最终 injector 所需的所有类型是否可解
复杂依赖最常卡在类型精度和包边界上。比如 *gin.Engine 和 gin.IRouter 看似兼容,但 wire 会当作完全不同的类型处理;又比如 provider 在 internal/db 包,但 injector 在 cmd/app,即使导出也无法跨包识别——必须把 provider 放到 injector 同包,或通过显式 import + wire.NewSet 暴露。


















