$ go get -u github.com/rathil/rdi
Then import it:
import "github.com/rathil/rdi"
type IUser interface{}
type User struct{}
func NewIUser() (IUser, error) {
return &User{}, nil
}
func NewUserPoint() (*User, error) {
return &User{}, nil
}
func NewUser() User {
return User{}
}
type IDevice interface{}
type Device struct{
User *User
}
var sameErrorDevice = fmt.Errorf(`same device error`)
func NewDevicePoint(user *User, sameVar int) (*Device, error) {
if sameVar > 5 {
return nil, sameErrorDevice
}
return &Device{user}, nil
}
func NewDevice(user *User) (Device, error) {
return Device{user}, nil
}
func NewIDevicePoint(user *User) (IDevice, error) {
return &Device{user}, nil
}
di := standard.New()
user := NewUserPoint()
// ...
if err := di.Provide(user); err != nil {
panic(err)
}
Or using a constructor directly:
if err := di.Provide(NewUserPoint); err != nil {
panic(err)
}
Or with MustProvide:
di.MustProvide(NewIUser)
di.MustProvide(NewUserPoint)
di.MustProvide(NewUser)
user := NewIUser()
// ...
di.MustProvide(user) // Will register *User instead of IUser
di.MustProvide(NewIUser)
if err := di.Invoke(func(user *User) {
// ...
}); err != nil {
panic(err)
}
With error handling:
var someError = fmt.Errorf(`some error`)
// ...
if err := di.Invoke(func(user *User) error {
// ...
if varName > 5 {
return someError
}
return nil
}); err != nil {
if !errors.Is(err, someError) {
panic(err)
}
}
Chaining multiple invocations:
di.
MustInvoke(func(user IUser) {
// ...
}).
MustInvoke(func(user *User) {
// ...
}).
MustInvoke(func(user User) {
// ...
})
By default, providers are singleton and cached after first creation:
di := standard.New().
MustProvide(func() context.Context { // Will be called once
return context.Background()
})
di.MustInvoke(func(c context.Context) {})
di.MustInvoke(func(c context.Context) {})
To get a new instance on each request, use WithTransient():
di := standard.New().
MustProvide(func() context.Context { // It will be called every time when the context is requested
return context.Background()
}, rdi.WithTransient())
di.MustInvoke(func(c context.Context) {})
di.MustInvoke(func(c context.Context) {})
You can create a child container to override or extend dependencies:
di := standard.New().
MustProvide(22).
MustProvide(NewUserPoint)
di.MustInvoke(func(data int) { /* data == 22 */ })
diCopy := standard.NewWithParent(di).
MustProvide(NewDevicePoint)
diCopy.MustInvoke(func(data int) { /* data == 22 */ })
err := diCopy.Invoke(func(device *Device) {
// ...
})
// err == sameErrorDevice if input int is > 5
diCopyOfCopy := standard.NewWithParent(diCopy).
MustProvide(3)
diCopyOfCopy.MustInvoke(func(data int) { /* data == 3 */ })
diCopyOfCopy.MustInvoke(func(device *Device) {
// ...
})
Or you can use the integrated override functionality:
standard.New().
MustProvide(22).
MustOverride(15).
MustInvoke(func(data int) { /* data == 15 */ })