golang-google-wire
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePersona: You are a Go architect using wire for compile-time DI. You let the compiler catch missing dependencies, treat as committed source, and re-run after every graph change.
wire_gen.gowire ./...角色定位: 你是一名使用wire实现编译时DI的Go架构师。你会让编译器捕捉缺失的依赖,将作为已提交的源码对待,并且在每次依赖图变更后重新运行。
wire_gen.gowire ./...Using google/wire for Compile-Time Dependency Injection in Go
使用google/wire在Go中实现编译时依赖注入
Code-generation DI toolkit. Wire resolves the dependency graph at compile time and emits plain Go constructor calls — no runtime container, no reflection. Errors appear when you run , not at first request.
wire ./...Note: was archived in August 2025 (feature-complete; bug fixes still accepted).
google/wireThis skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform.
bash
go install github.com/google/wire/cmd/wire@latest
go get github.com/google/wire代码生成式DI工具包。Wire在编译时解析依赖图,并生成纯Go构造函数调用——无需运行时容器,无需反射。错误会在你运行时出现,而非首次请求时。
wire ./...注意:已于2025年8月归档(功能完善;仍接受bug修复)。
google/wire本技能内容并非详尽无遗。如需更多信息,请参考库文档和代码示例。Context7可作为发现平台提供帮助。
bash
go install github.com/google/wire/cmd/wire@latest
go get github.com/google/wirewire vs. Runtime DI
wire vs. 运行时DI
| Concern | wire | dig / fx / samber/do |
|---|---|---|
| Resolution | Compile time (codegen) | Runtime (reflection) |
| Error detection | | First |
| Runtime container | None — plain Go calls | Present |
| Lifecycle hooks | Not built in | fx: OnStart/OnStop |
| Generated files | | None |
For lifecycle, lazy loading, and a full matrix see .
samber/cc-skills-golang@golang-dependency-injection| 关注点 | wire | dig / fx / samber/do |
|---|---|---|
| 依赖解析时机 | 编译时(代码生成) | 运行时(反射) |
| 错误检测时机 | 运行 | 首次 |
| 运行时容器 | 无——纯Go调用 | 存在 |
| 生命周期钩子 | 未内置 | fx: OnStart/OnStop |
| 生成文件 | | 无 |
如需了解生命周期、延迟加载及完整对比,请查看。
samber/cc-skills-golang@golang-dependency-injectionProviders
提供者(Providers)
A provider is any Go function — inputs are dependencies, outputs are provided types. Three return forms:
go
func NewConfig() *Config { return &Config{Addr: ":8080"} }
func NewDB(cfg *Config) (*sql.DB, error) { return sql.Open("postgres", cfg.DSN) }
func NewRedis(cfg *Config) (*redis.Client, func(), error) { // cleanup chained in reverse order
c := redis.NewClient(&redis.Options{Addr: cfg.RedisAddr})
return c, func() { c.Close() }, nil
}提供者是任意Go函数——输入为依赖项,输出为提供的类型。有三种返回形式:
go
func NewConfig() *Config { return &Config{Addr: ":8080"} }
func NewDB(cfg *Config) (*sql.DB, error) { return sql.Open("postgres", cfg.DSN) }
func NewRedis(cfg *Config) (*redis.Client, func(), error) { // 清理函数按逆序执行
c := redis.NewClient(&redis.Options{Addr: cfg.RedisAddr})
return c, func() { c.Close() }, nil
}Provider Sets
提供者集合(Provider Sets)
wire.NewSetgo
// infra/wire.go
var InfraSet = wire.NewSet(
NewConfig,
NewDB,
NewRedis,
)
// service/wire.go
var ServiceSet = wire.NewSet(
NewUserRepo,
NewUserService,
wire.Bind(new(UserStore), new(*UserRepo)), // interface binding
)Keep sets small: library sets expose a stable surface (adding inputs or removing outputs breaks downstream injectors). One set per package is a useful default.
wire.NewSetgo
// infra/wire.go
var InfraSet = wire.NewSet(
NewConfig,
NewDB,
NewRedis,
)
// service/wire.go
var ServiceSet = wire.NewSet(
NewUserRepo,
NewUserService,
wire.Bind(new(UserStore), new(*UserRepo)), // 接口绑定
)保持集合规模较小:库集合应暴露稳定的接口(添加输入或移除输出会破坏下游注入器)。每个包对应一个集合是实用的默认方案。
Injectors and //go:build wireinject
//go:build wireinject注入器与//go:build wireinject
//go:build wireinjectThe injector file declares the initialization function. Wire generates its body into and replaces the stub.
wire_gen.gogo
//go:build wireinject
package main
import "github.com/google/wire"
// Wire generates the body of this function.
func InitApp() (*App, func(), error) {
wire.Build(InfraSet, ServiceSet, NewApp)
return nil, nil, nil // replaced by codegen
}The tag prevents the stub from being compiled into the binary — only (which has no such tag) makes it through . Without this tag, both files define the same function, causing a compile error.
//go:build wireinjectwire_gen.gogo buildAlternative syntax when a dummy return is inconvenient:
go
func InitApp() (*App, func(), error) {
panic(wire.Build(InfraSet, ServiceSet, NewApp))
}注入器文件声明初始化函数。Wire会将函数体生成到中并替换存根。
wire_gen.gogo
//go:build wireinject
package main
import "github.com/google/wire"
// Wire会生成此函数的函数体。
func InitApp() (*App, func(), error) {
wire.Build(InfraSet, ServiceSet, NewApp)
return nil, nil, nil // 会被代码生成替换
}//go:build wireinjectwire_gen.gogo build当虚拟返回值不方便时的替代语法:
go
func InitApp() (*App, func(), error) {
panic(wire.Build(InfraSet, ServiceSet, NewApp))
}Interface Bindings
接口绑定
Wire forbids implicit interface satisfaction — you must declare bindings explicitly so the graph is unambiguous when multiple types implement the same interface.
go
var Set = wire.NewSet(
NewPostgresUserRepo,
wire.Bind(new(UserStore), new(*PostgresUserRepo)), // tell wire: *PostgresUserRepo satisfies UserStore
)Explicit bindings prevent graph breakage when a new type implementing the same interface is added elsewhere.
Wire禁止隐式接口实现——你必须显式声明绑定,以便当多个类型实现同一接口时依赖图保持明确。
go
var Set = wire.NewSet(
NewPostgresUserRepo,
wire.Bind(new(UserStore), new(*PostgresUserRepo)), // 告知wire:*PostgresUserRepo实现了UserStore
)显式绑定可防止当其他地方添加了实现同一接口的新类型时依赖图被破坏。
Struct Providers and Values
结构体提供者与值
wire.Structwire:"-"go
wire.Struct(new(Server), "Logger", "DB") // inject named fields
wire.Struct(new(Server), "*") // inject all non-excluded fields
wire.Value(Foo{X: 42}) // constant expression (no fn calls / channels)
wire.InterfaceValue(new(io.Reader), os.Stdin) // interface-typed literal
wire.FieldsOf(new(Config), "DSN", "Addr") // promote struct fields as graph nodesSee advanced.md for the exclusion tag and details.
wire:"-"wire.FieldsOfwire.Structwire:"-"go
wire.Struct(new(Server), "Logger", "DB") // 注入指定字段
wire.Struct(new(Server), "*") // 注入所有未排除的字段
wire.Value(Foo{X: 42}) // 常量表达式(无函数调用/通道)
wire.InterfaceValue(new(io.Reader), os.Stdin) // 接口类型字面量
wire.FieldsOf(new(Config), "DSN", "Addr") // 将结构体字段提升为依赖图节点关于排除标记和的详细信息,请查看advanced.md。
wire:"-"wire.FieldsOfDisambiguating Duplicate Types
区分重复类型
Wire forbids two providers for the same type. Wrap the underlying type in distinct named types so each has exactly one provider:
go
type PrimaryDSN string
type ReplicaDSN stringWire禁止同一类型存在两个提供者。将底层类型包装为不同的命名类型,使每个类型恰好有一个提供者:
go
type PrimaryDSN string
type ReplicaDSN stringFull Application Example
完整应用示例
go
// wire.go — injector, excluded from binary via build tag
//go:build wireinject
package main
func InitApp() (*App, func(), error) {
wire.Build(config.ConfigSet, infra.InfraSet, service.ServiceSet, NewApp)
return nil, nil, nil
}
// main.go
func main() {
app, cleanup, err := InitApp()
if err != nil { log.Fatal(err) }
defer cleanup()
app.Run()
}Wire generates (plain Go, committed, DO NOT EDIT). For a full example with per-package sets, cleanup-heavy graphs, and generated output, see recipes.md.
wire_gen.gogo
// wire.go —— 注入器,通过构建标签排除在二进制文件之外
//go:build wireinject
package main
func InitApp() (*App, func(), error) {
wire.Build(config.ConfigSet, infra.InfraSet, service.ServiceSet, NewApp)
return nil, nil, nil
}
// main.go
func main() {
app, cleanup, err := InitApp()
if err != nil { log.Fatal(err) }
defer cleanup()
app.Run()
}Wire会生成(纯Go代码,已提交,请勿编辑)。如需包含每个包集合、大量清理操作的依赖图及生成输出的完整示例,请查看recipes.md。
wire_gen.goCodegen Workflow
代码生成工作流
bash
wire ./... # regenerate all injectors in the module
wire check ./... # validate graph without regenerating (fast CI check)Run after every constructor signature change. Add to injector files so also works. Commit — it must stay in sync for CI builds.
wire ./...//go:generate go run github.com/google/wire/cmd/wirego generate ./...wire_gen.gobash
wire ./... # 重新生成模块中的所有注入器
wire check ./... # 验证依赖图但不重新生成(快速CI检查)每次构造函数签名变更后运行。在注入器文件中添加,这样也能生效。提交——它必须保持同步以支持CI构建。
wire ./...//go:generate go run github.com/google/wire/cmd/wirego generate ./...wire_gen.goBest Practices
最佳实践
- Never edit — it is overwritten on every
wire_gen.gorun. Treat it as a build artifact that happens to be committed; source of truth is the provider and injector files.wire ./... - Always add to injector files — omitting it causes duplicate-symbol compile errors because both the stub and the generated file define the same function.
//go:build wireinject - Use named types to distinguish values of the same underlying type — wire enforces one provider per type; named types like let you have
type DSN stringandPrimaryDSNcoexist.ReplicaDSN - Keep library provider sets minimal and backward-compatible — adding new required inputs breaks downstream injectors; removing outputs does too. Introduce only newly-created types in the same release.
- Return from cleanup providers and let wire chain them — wire generates the correct reverse-order cleanup and handles partial failures (if construction fails midway, only already-built cleanups run).
(T, func(), error) - Keep injector files focused — one function per file, one package import at a time. Fat injectors with dozens of arguments are hard to reason about; delegate to per-package sets.
wire.Build
- 永远不要编辑——每次运行
wire_gen.go都会覆盖它。将其视为已提交的构建产物;真相源是提供者和注入器文件。wire ./... - 始终为注入器文件添加——省略它会导致重复符号编译错误,因为存根和生成文件都定义了相同的函数。
//go:build wireinject - 使用命名类型区分相同底层类型的值——Wire强制每个类型只有一个提供者;像这样的命名类型允许
type DSN string和PrimaryDSN共存。ReplicaDSN - 保持库提供者集合最小且向后兼容——添加新的必填输入会破坏下游注入器;移除输出也会如此。仅在同一版本中引入新创建的类型。
- 从清理提供者返回并让wire链式处理它们——Wire会生成正确的逆序清理逻辑,并处理部分失败(如果构建中途失败,仅会运行已构建完成的清理函数)。
(T, func(), error) - 保持注入器文件聚焦——每个文件一个函数,每次导入一个包。包含数十个参数的臃肿注入器难以理解;委托给每个包的集合。
wire.Build
Common Mistakes
常见错误
| Mistake | Fix |
|---|---|
Editing | Never edit it. Change providers or injectors and re-run |
Missing | Add the tag as the very first line of every injector file. |
Two providers returning | Wrap with named types ( |
Injecting an interface without | Add |
Forgetting to re-run | Run wire before |
Calling | Wire returns nil cleanup on construction error; guard with |
| 错误 | 修复方案 |
|---|---|
手动编辑 | 永远不要编辑它。修改提供者或注入器后重新运行 |
缺少 | 在每个注入器文件的第一行添加该标签。 |
有两个返回 | 使用命名类型包装( |
未使用 | 在提供者集合中添加 |
变更后忘记重新运行 | 在 |
未检查nil就调用 | Wire在构建错误时会返回nil清理函数;使用 |
Testing
测试
Wire generates plain Go constructors, so unit tests use manual injection — no container to clone or reset. For testing patterns (test injectors swapping real providers for fakes, CI stale-check for ), see testing.md.
wire_gen.goWire生成纯Go构造函数,因此单元测试使用手动注入——无需克隆或重置容器。如需测试模式(测试注入器将真实提供者替换为模拟实现、CI检查是否过时),请查看testing.md。
wire_gen.goFurther Reading
进一步阅读
- advanced.md — cleanup chains, multiple injectors, set nesting, error catalogue, codegen flags, quick reference
- recipes.md — HTTP server, multi-injector build, cleanup-heavy graph, CLI embedding
- testing.md — test injectors, fake bindings, CI stale check
- advanced.md —— 清理链、多注入器、集合嵌套、错误目录、代码生成标志、速查手册
- recipes.md —— HTTP服务器、多注入器构建、大量清理操作的依赖图、CLI嵌入
- testing.md —— 测试注入器、模拟绑定、CI过时检查
Cross-References
交叉引用
- → See skill for DI concepts and library comparison
samber/cc-skills-golang@golang-dependency-injection - → See skill for runtime reflection-based DI without lifecycle
samber/cc-skills-golang@golang-uber-dig - → See skill for runtime DI with lifecycle hooks, modules, and signal-aware Run()
samber/cc-skills-golang@golang-uber-fx - → See skill for generics-based DI without reflection
samber/cc-skills-golang@golang-samber-do - → See skill for interface design patterns
samber/cc-skills-golang@golang-structs-interfaces - → See skill for general testing patterns
samber/cc-skills-golang@golang-testing
If you encounter a bug or unexpected behavior in google/wire, open an issue at https://github.com/google/wire/issues.
- → 如需了解DI概念及库对比,请查看技能
samber/cc-skills-golang@golang-dependency-injection - → 如需了解无生命周期的基于反射的运行时DI,请查看技能
samber/cc-skills-golang@golang-uber-dig - → 如需了解带生命周期钩子、模块和信号感知Run()的运行时DI,请查看技能
samber/cc-skills-golang@golang-uber-fx - → 如需了解基于泛型的无反射DI,请查看技能
samber/cc-skills-golang@golang-samber-do - → 如需了解接口设计模式,请查看技能
samber/cc-skills-golang@golang-structs-interfaces - → 如需了解通用测试模式,请查看技能
samber/cc-skills-golang@golang-testing
如果在google/wire中遇到bug或意外行为,请在https://github.com/google/wire/issues提交问题。