golobby / container Goto Github PK
View Code? Open in Web Editor NEWA lightweight yet powerful IoC dependency injection container for the Go programming language
License: MIT License
A lightweight yet powerful IoC dependency injection container for the Go programming language
License: MIT License
I just installed the package and gave it a go. I was following the README code examples, but I got some type errors.
Installation:
$ go get github.com/golobby/container/v3
My code following README example:
type Test interface {
Test()
}
type TestImpl struct {
}
func (iml *TestImpl) Test() {
fmt.Println("Test")
}
func main() {
// Bind Config interface to JsonConfig struct
err := container.Singleton(func() Test {
return &TestImpl{}
})
var c TestImpl
err := container.Resolve(&c)
// `c` will be the instance of JsonConfig
}
Errors:
container.Singleton((func() Test literal)) (no value) used as valuecompilerTooManyValues
Resolve not declared by package containercompilerUndeclaredImportedName
It looks like there:
Is it an issue with outdated documentation, or am I doing something weird here?
Thanks :)
i am looking for an ioc container that can solve circular dependency.
i cannot find source code which do detect circular dependency from the project.
anyway, this project design is a very useful example for me, thank you!
not work if i add go.work file with inner dependencies
i've added some example code below and i've found that the singleton is created twice.
c := container.New()
c.Singleton(func() (ExampleService, error) {
fmt.Println("singleton created")
return CreateExampleService()
})
the issue only occurs because the resolver function returns a 2-tuple of (ExampleService, error)
the issue is happening because of the invoke call happening in this loop (I think) https://github.com/golobby/container/blob/master/container.go#L101
It could be a better solution to return nil if there is no appropriate concrete instead of panic.
It could be nice if it supports receiving implementations when the requested type is implementation not interface.
Hello, I am using your great library for Dependency injection.
However, I want to retrieve errors when binding.
For instance, my code below is to open SQLite DB, but when Opening DB failed, I have to call panic() to show an error.
container.Singleton(func() *gorm.DB {
DBFile := "/tmp/test.db"
dialector := sqlite.Open(DBFile)
db, err := gorm.Open(dialector)
if err != nil {
panic(err)
}
return db.Debug()
})
So, I want you to enable me to run the code like below to retrieve the error.
Right now, when error occurs, the code below just cause nil reference error.
container.Singleton(func() (*gorm.DB, error) {
DBFile := "/tmp/test.db"
dialector := sqlite.Open(DBFile)
db, err := gorm.Open(dialector)
if err != nil {
return nil, err
}
return db.Debug(), nil
})
Thanks,
First of all, thanks for this amazing library.
Here is what my singleton call is like
container.Singleton(func() (*gorm.DB, error) {
dbFile := "/tmp/test.db"
dialector := sqlite.Open(dbFile)
db, err := gorm.Open(dialector)
if err != nil {
return nil, err
}
return db.Debug(), nil
})
But I am always getting panic: interface conversion: interface is nil, not error
even when error is nil.
I think there should be a check for nil before casting to error type in
container/pkg/container/container.go
Line 74 in 800c8e1
Can you please look into it?
Thanks
A feature that would be extremely useful would be extremely useful would be to support the creation of child or cloned containers. A child container is more complex, being an empty container with a reference to a parent container and walking up the hierarchy as it tries to resolve types, but a clone would just duplicate existing bindings at the point it was cloned and then set itself as the Container object binding in place of the original container.
The use case for this is to allow for a "scoped" container to be created. For example when handling a HTTP request objects like a context.Context generated by a HTTP request, as well as the Request and ResponseWriter could be populated to a child/clone container while handling the request and then the Call method could be used to populate required Classes for a handler method.
Singleton resolvers that return error during resolution should not cache the concrete instance
Given the following Go struct
type Foo struct {
Value string
}
func NewFoo(value string) *Foo {
return &Foo{ Value: value }
}
When using the container in this package if I register a resolver for a singleton where it could conditionally fail based on some expectation:
container.Singleton(func() (*Foo, error) {
if expectationsAreMet {
return NewFoo("test"), nil
} else {
return nil, errors.New("cannot create this type right now")
}
})
Then when the caller attempts to re-resolve the type the cached nil
value is returned instead of the resolver trying again.
var instance *Foo
err := container.Resolve(&instance) // Resolution can fail here if external expectation is not met
if err != nil {
// Perform some bootstrapping to meeting required expectation
external.MeetExpectation()
// Try to resolve the type again after expectations are met
err = container.Resolve(&instance) // Resolver should try again now that expectation has been met.
}
The registered singleton resolver should run again since the original resolution failed and return an error
The nil
value is stored as the concrete value for the singleton and is returned on subsequent Resolve(...)
calls.
We have some bindings of named implementations:
container.NamedSingleton("square", func() Shape {
return &Rectangle{}
})
container.NamedSingleton("rounded", func() Shape {
return &Circle{}
})
How to get all registered implementations of Shape?
Something like this:
var shapes map[string]Shape
container.ResolveAll(&shapes)
if this is not implemented, then it seems to me it would be a cool feature.
I just installed the package and gave it a go. I was following the README code examples, but I got some type errors.
Installation:
$ go get github.com/golobby/container/v3
go.sum:
github.com/golobby/container v1.3.0 h1:Pgk8fK9fJHuZqU924Bl8+DY2/n9jCUtsSKfiOctdQ9A=
github.com/golobby/container v1.3.0/go.mod h1:6yAH4QK+Hi8HxGuCJuAGiqS/a5n8YP+4bXNpPdKzLVM=
github.com/golobby/container/v3 v3.3.0 h1:ohPSWUUY67yvOhIBVC9Wv1pnsh8iOwRS0U1M1bjKBG8=
github.com/golobby/container/v3 v3.3.0/go.mod h1:RDdKpnKpV1Of11PFBe7Dxc2C1k2KaLE4FD47FflAmj0=
My code following README example:
type Test interface {
Test()
}
type TestImpl struct {
}
func (iml *TestImpl) Test() {
fmt.Println("Test")
}
func main() {
// Bind Config interface to JsonConfig struct
err := container.Singleton(func() Test {
return &TestImpl{}
})
var c TestImpl
err := container.Resolve(&c)
// `c` will be the instance of JsonConfig
}
Errors:
container.Singleton((func() Test literal)) (no value) used as valuecompilerTooManyValues
Resolve not declared by package containercompilerUndeclaredImportedName
It looks like there:
Is it an issue with outdated documentation, or am I doing something weird here?
Thanks :)
Hi there,
This is a great component to what I'm looking for... :) I'd like to integrate VIper with Container:
yaml
structs
that directly maps to the filesI'd like to do something similar to ConfigurationProperties
of SpringBoot from https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/boot-features-external-config.html
Has someone worked on something similar?
Thank you
I am using golobby/container/v3
:
type Database interface {
}
type DatabaseImpl struct {
MySql interface{}
PgSql interface{}
}
container.Singleton(func() Database {
return &DatabaseImpl {
MySql: mysql.CreateConnection(),
PgSql: pgsql.CreateConnection(),
}
})
Now I want to get an instance of MySql
connection, so how can I get it?
I try to do:
var d Database
container.Resolve(&d)
result, _ := d.MySql.Query(...)
but i get an error type Database has no field or method MySql
Is there a way to resolve multiple items by its common interface?
Example:
IPlugin abstract
PluginA concrete
PluginB concrete
register both plugins by IPlugin
resolve []IPlugin where both plugins will be returned
It will be nice to be able to register and access container bindings asynchronously (e.g. registration of some new binding during application run while some another parts of app resolves existent bindings). Probably some synchronized version of Container
can be created for such a purposes instead of changing existent one, but anyway it will be useful feature.
The resolver function could return multiple implementations so it can bind some abstractions at once and prevent panic.
great library, would you reconsider this issue #4 and add "must" variants for the container methods.
container.MustSingleton
container.MustTransient
etc.
all container methods that can return an error and are typically called in main() or init() could have a "must" variant.
the must variant panics if an error occurs instead of returning it.
for example, in my application I register dependencies with the container in main() and the "if err != nil { panic(err) }" handling makes the code harder to read but if we leave it out then invalid container configuration can silently occur.
Hi, I am working on a project where we use the container library.
We are trying to "tune" the usage of the DI container with custom tags, to get rid of call-chains like
func NewInstance() *Instance {
var repo repository.Notifications
var bridge fcm.Bridge
var timeProvider tp.TimeProvider
main.DI.Make(&repo)
main.DI.Make(&bridge)
main.DI.Make(&timeProvider)
// return instance...
}
What I want to do is to mark some struct fields with a custom tag, let's say di:"inject"
to automatically inject the fields at some point (like execute
call).
What I've already achieved is the following code:
type Instance struct {
context ctx.Context
repo repository.Notifications `di:"bind"`
...
}
func inject(gc GoCase) {
rv := reflect.ValueOf(gc).Elem()
t := rv.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
rvField := rv.Field(i)
if value, ok := field.Tag.Lookup("di"); ok {
if value == "bind" {
y := reflect.NewAt(rvField.Type(), unsafe.Pointer(rvField.UnsafeAddr())).Elem()
receiverType := y.Type()
concrete, ok := DI[receiverType] // DI is the app-container
if !ok {
panic("concrete not found for the abstraction" + receiverType.String())
}
// Concrete found, but how do I get instance/receiver from the concrete?
// Do I need to use the reflection here? Or maybe it's better to add/expose
// a possibility to do that in the library?
fmt.Print(concrete) // just for testing
}
}
}
}
My wonderings are explained in the comment.
And I see a few possibilities:
GetConcrete(Type)
)di:"inject"
(I can implement it, but first I would like to know what you think about it).Thanks for your input!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.