General purpose Go utilities.
Mostly type-safe IoC container.
context.Context
basedbind.*
methods to setup and resolve bindings- Thread-safe
// first we define some types
// - Database is our database interface
// - sqlDBImpl implements the interfaces
// - dao uses the database
type Database interface { /* ... */ }
type sqlDBImpl struct {
Username string `bind:"username"` // get the username
Password string `bind:"password"` // get the password
Host string `bind:"host"` // get the host
Port int `bind:"port"` // get the port
}
type dao struct {
DB Database `bind:"-"` // get the database
}
ctx, _ = bind.Configure(ctx,
bind.String("admin").For("username"),
bind.String("s3cr3t").For("password"),
bind.String("localhost").For("host"),
bind.Int(5432).For("port"),
bind.ImplementationOnce[Database, *sqlDBImpl](), // bind Database to one instance of *sqlDBImpl
)
// get Database which will be the *sqlDBImpl instance
// this is useful if you'd manually fetch dependencies
// or assign private fields
db := bind.Get[Database](ctx)
// this returns a new instance of *dao with all fields
// that contain the bind tag populated
dao := bind.New[*dao](ctx)
The API allows for various setups. Note that a type is considered a leaf if there is no
other mapping for that type. Hence if bind.Implementation[X, Y]
and both bind.Instance[Y]
have
been configured the instance binding is the result of the injection of X
.
bind.Configure(ctx, bindings...)
: configure bindings in a context; can overwrite existing bindings of the parent contextbind.Implementation[X, Y]()
: bindY
forX
, return instances ofY
ifY
is a leafbind.Once[X]()
: bindX
for exactly one instancebind.ImplementationOnce[X, Y]()
: bind exactly one instance ofY
forX
bind.Instance[X](inst X)
: bindX
toinst
bind.Many[X]()
: bindX
and return instances ofX
bind.Provider[X](f func() (X, error))
: bindX
to invocations off
bind.New[X](ctx)
: resolveX
or create a new instance ofX
(X doesn't need to be bound)bind.Get[X](ctx)
: resolveX
bind.For[X](ctx, scope)
: resolveX
forscope
bind.MaybeNew[X](ctx)
: resolveX
or create a new instance ofX
; return error instead of panicbind.MaybeGet[X](ctx)
: resolveX
; return error instead of panicbind.MaybeFor[X](ctx, scope)
: resolveX
forscope
; return error instead of panicbind.Initializer
: When implemented, callsInitAfter
after a type was initialized
bind.Implementation[Iface, Impl]()
can't guarantee Impl
is assignable to Iface
at compile time and panics at runtime.
Internally there are several instances of any
and reflection is still used given the nature of how Go generics
work.
Note though that we can use generics to ensure that certain types exist and the use of any
in the
public API is non-existent.
Utilities to work with channels.
Safe*
methods to perform common actions on channels that won't panic (read: either you don't care or it's a code smell)Maybe*
methods to perform common patterns with less ceremony
Utilities to work with slices.