golang-samber-do
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePersona: You are a Go architect setting up dependency injection. You keep the container at the composition root, depend on interfaces not concrete types, and treat provider errors as first-class failures.
角色定位: 你是一名负责搭建依赖注入的Go架构师。你将容器置于组合根,依赖接口而非具体类型,并将提供者错误视为首要故障。
Using samber/do for Dependency Injection in Go
使用samber/do实现Go语言依赖注入
Type-safe dependency injection toolkit for Go based on Go 1.18+ generics.
Official Resources:
This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform.
DO NOT USE v1 OF THIS LIBRARY. INSTALL v2 INSTEAD:
bash
go get -u github.com/samber/do/v2基于Go 1.18+泛型的类型安全Go语言依赖注入工具包。
官方资源:
本技能内容并非详尽无遗。如需更多信息,请参考库文档和代码示例。Context7可作为一个发现平台提供帮助。
请勿使用该库的v1版本,请安装v2版本:
bash
go get -u github.com/samber/do/v2Core Concepts
核心概念
The Injector (Container)
注入器(容器)
go
import "github.com/samber/do/v2"
injector := do.New()go
import "github.com/samber/do/v2"
injector := do.New()Service Types
服务类型
- Lazy (default): Created when first requested
- Eager: Created immediately when the container starts
- Transient: New instance created on every request
- Value: Pre-created value, no instantiation
- 延迟加载(默认):首次请求时创建实例
- 立即加载:容器启动时立即创建实例
- 瞬时型:每次请求都创建新实例
- 值类型:预先创建的值,无需实例化
Provider Functions
提供者函数
Services MUST be registered via provider functions:
go
type Provider[T any] func(i Injector) (T, error)服务必须通过提供者函数注册:
go
type Provider[T any] func(i Injector) (T, error)Basic Usage
基础用法
1. Define and Register Services
1. 定义并注册服务
Follow "Accept Interfaces, Return Structs":
go
// Register a service (lazy by default)
do.Provide(injector, func(i do.Injector) (Database, error) {
return &PostgreSQLDatabase{connString: "postgres://..."}, nil
})
// Register a pre-created value
do.ProvideValue(injector, &Config{Port: 8080})
// Register a transient service (new instance each time)
do.ProvideTransient(injector, func(i do.Injector) (*Logger, error) {
return &Logger{}, nil
})
// Register an eager service (created immediately)
do.Provide(injector, do.Eager(&Config{Port: 8080}))遵循“接受接口,返回结构体”原则:
go
// 注册服务(默认延迟加载)
do.Provide(injector, func(i do.Injector) (Database, error) {
return &PostgreSQLDatabase{connString: "postgres://..."}, nil
})
// 注册预先创建的值
do.ProvideValue(injector, &Config{Port: 8080})
// 注册瞬时型服务(每次请求创建新实例)
do.ProvideTransient(injector, func(i do.Injector) (*Logger, error) {
return &Logger{}, nil
})
// 注册立即加载服务(容器启动时立即创建)
do.Provide(injector, do.Eager(&Config{Port: 8080}))2. Invoke Services
2. 调用服务
The container MUST only be accessed at the composition root:
go
// Invoke with error handling
db, err := do.Invoke[Database](injector)
// MustInvoke panics on error (use when confident service exists)
db := do.MustInvoke[Database](injector)容器只能在组合根中访问:
go
// 带错误处理的调用
db, err := do.Invoke[Database](injector)
// MustInvoke在出错时会panic(当你确定服务存在时使用)
db := do.MustInvoke[Database](injector)3. Service Dependencies
3. 服务依赖
go
func NewUserService(i do.Injector) (UserService, error) {
db := do.MustInvoke[Database](i)
cache := do.MustInvoke[Cache](i)
return &userService{db: db, cache: cache}, nil
}
do.Provide(injector, NewUserService)go
func NewUserService(i do.Injector) (UserService, error) {
db := do.MustInvoke[Database](i)
cache := do.MustInvoke[Cache](i)
return &userService{db: db, cache: cache}, nil
}
do.Provide(injector, NewUserService)4. Implicit Aliasing (Preferred)
4. 隐式别名(推荐)
Register a concrete type and invoke as an interface without explicit aliasing:
go
// Register concrete type
do.Provide(injector, func(i do.Injector) (*PostgreSQLDatabase, error) {
return &PostgreSQLDatabase{}, nil
})
// Invoke directly as interface (implicit aliasing)
db := do.MustInvokeAs[Database](injector)注册具体类型并直接以接口类型调用,无需显式别名:
go
// 注册具体类型
do.Provide(injector, func(i do.Injector) (*PostgreSQLDatabase, error) {
return &PostgreSQLDatabase{}, nil
})
// 直接以接口类型调用(隐式别名)
db := do.MustInvokeAs[Database](injector)5. Named Services
5. 命名服务
Register multiple services of the same type:
go
do.ProvideNamed(injector, "primary-db", func(i do.Injector) (*Database, error) {
return &Database{URL: "postgres://primary..."}, nil
})
mainDB := do.MustInvokeNamed[*Database](injector, "primary-db")注册多个同类型服务:
go
do.ProvideNamed(injector, "primary-db", func(i do.Injector) (*Database, error) {
return &Database{URL: "postgres://primary..."}, nil
})
mainDB := do.MustInvokeNamed[*Database](injector, "primary-db")Package Organization
包组织
Use to organize service registration by module:
do.Package()go
// infrastructure/package.go
var Package = do.Package(
do.Lazy(func(i do.Injector) (*postgres.DB, error) {
cfg := do.MustInvoke[*Config](i)
return postgres.Connect(cfg.DatabaseURL)
}),
do.Lazy(func(i do.Injector) (*redis.Client, error) {
cfg := do.MustInvoke[*Config](i)
return redis.NewClient(cfg.RedisURL), nil
}),
)
// main.go
injector := do.New(infrastructure.Package, service.Package)使用按模块组织服务注册:
do.Package()go
// infrastructure/package.go
var Package = do.Package(
do.Lazy(func(i do.Injector) (*postgres.DB, error) {
cfg := do.MustInvoke[*Config](i)
return postgres.Connect(cfg.DatabaseURL)
}),
do.Lazy(func(i do.Injector) (*redis.Client, error) {
cfg := do.MustInvoke[*Config](i)
return redis.NewClient(cfg.RedisURL), nil
}),
)
// main.go
injector := do.New(infrastructure.Package, service.Package)Full Application Setup
完整应用搭建
go
func main() {
injector := do.New(
infrastructure.Package,
repository.Package,
service.Package,
transport.Package,
)
server := do.MustInvoke[*http.Server](injector)
go server.ListenAndServe()
_ = injector.ShutdownOnSignalsWithContext(context.Background(), os.Interrupt)
}go
func main() {
injector := do.New(
infrastructure.Package,
repository.Package,
service.Package,
transport.Package,
)
server := do.MustInvoke[*http.Server](injector)
go server.ListenAndServe()
_ = injector.ShutdownOnSignalsWithContext(context.Background(), os.Interrupt)
}Best Practices
最佳实践
- Depend on interfaces, not concrete types — lets you swap implementations in tests without touching production code
- Each service should have one job — services with multiple responsibilities are harder to test and harder to replace
- Keep dependency trees shallow — chains beyond 3-4 levels make initialization order fragile and errors harder to trace
- Handle errors in provider functions — a silently failing provider creates a broken service that crashes later in unexpected places
- Use scopes to organize services by lifecycle — request-scoped services prevent leaks, global services prevent redundant initialization
For scopes, lifecycle management, struct injection, and debugging, see Advanced Usage.
For testing patterns (cloning, overrides, mocks), see Testing.
- 依赖接口而非具体类型——这样你可以在测试中替换实现,无需修改生产代码
- 每个服务应只负责一项工作——承担多个职责的服务更难测试和替换
- 保持依赖树较浅——超过3-4层的依赖链会让初始化顺序变得脆弱,且错误更难追踪
- 在提供者函数中处理错误——静默失败的提供者会创建一个有问题的服务,在后续意想不到的地方崩溃
- 使用作用域按生命周期组织服务——请求作用域的服务可防止内存泄漏,全局服务可避免重复初始化
如需了解作用域、生命周期管理、结构体注入和调试内容,请查看高级用法。
如需了解测试模式(克隆、覆盖、模拟),请查看测试。
Quick Reference
速查参考
Registration
注册
| Function | Purpose |
|---|---|
| Register lazy service (default) |
| Register named lazy service |
| Register pre-created value |
| Register named value |
| Register new instance each time |
| Register named transient service |
| Group service registrations |
| 函数 | 用途 |
|---|---|
| 注册延迟加载服务(默认) |
| 注册命名延迟加载服务 |
| 注册预先创建的值 |
| 注册命名值 |
| 注册每次请求创建新实例的服务 |
| 注册命名瞬时型服务 |
| 分组服务注册 |
Invocation
调用
| Function | Purpose |
|---|---|
| Get service (with error) |
| Get named service |
| Get first service matching interface |
| Inject into struct fields using tags |
| Get service (panic on error) |
| Get named service (panic on error) |
| Get service by interface (panic on error) |
| Inject into struct (panic on error) |
| 函数 | 用途 |
|---|---|
| 获取服务(带错误返回) |
| 获取命名服务 |
| 获取第一个匹配接口的服务 |
| 使用标签注入结构体字段 |
| 获取服务(出错时panic) |
| 获取命名服务(出错时panic) |
| 通过接口获取服务(出错时panic) |
| 注入结构体(出错时panic) |
Cross-References
交叉参考
- -> See skill for DI concepts, comparison, and when to adopt a DI library
samber/cc-skills-golang@golang-dependency-injection - -> 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
- -> 查看技能,了解DI概念、对比以及何时采用DI库
samber/cc-skills-golang@golang-dependency-injection - -> 查看技能,了解接口设计模式
samber/cc-skills-golang@golang-structs-interfaces - -> 查看技能,了解通用测试模式
samber/cc-skills-golang@golang-testing