General purpose Go utilities.
Mostly type-safe IoC container.
context.Contextbasedbind.*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](): bindYforX, return instances ofYifYis a leafbind.Once[X](): bindXfor exactly one instancebind.ImplementationOnce[X, Y](): bind exactly one instance ofYforXbind.Instance[X](inst X): bindXtoinstbind.Many[X](): bindXand return instances ofXbind.Provider[X](f func() (X, error)): bindXto invocations offbind.New[X](ctx): resolveXor create a new instance ofX(X doesn't need to be bound)bind.Get[X](ctx): resolveXbind.For[X](ctx, scope): resolveXforscopebind.MaybeNew[X](ctx): resolveXor create a new instance ofX; return error instead of panicbind.MaybeGet[X](ctx): resolveX; return error instead of panicbind.MaybeFor[X](ctx, scope): resolveXforscope; return error instead of panicbind.Initializer: When implemented, callsInitAfterafter 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.