diff --git a/container.go b/container.go index b6dfe4d..afda07a 100644 --- a/container.go +++ b/container.go @@ -117,7 +117,7 @@ func (c Container) arguments(function interface{}) ([]reflect.Value, error) { for i := 0; i < argumentsCount; i++ { abstraction := reflectedFunction.In(i) - if concrete, exist := c[abstraction][""]; exist { + if concrete, exist := c.concrete(abstraction); exist { instance, err := concrete.make(c) if err != nil { return nil, err @@ -131,6 +131,19 @@ func (c Container) arguments(function interface{}) ([]reflect.Value, error) { return arguments, nil } +func (c Container) concrete(abstraction reflect.Type) (*binding, bool) { + if concrete, exist := c[abstraction][""]; exist { + return concrete, true + } + for boundAbstraction, namedConcretes := range c { + if boundAbstraction.Implements(abstraction) { + concrete, exists := namedConcretes[""] + return concrete, exists + } + } + return nil, false +} + // Reset deletes all the existing bindings and empties the container. func (c Container) Reset() { for k := range c { diff --git a/container_test.go b/container_test.go index ee36562..88447fd 100644 --- a/container_test.go +++ b/container_test.go @@ -13,6 +13,10 @@ type Shape interface { GetArea() int } +type ReadOnlyShape interface { + GetArea() int +} + type Circle struct { a int } @@ -55,6 +59,28 @@ func TestContainer_Singleton(t *testing.T) { assert.NoError(t, err) } +func TestContainer_Singleton_Bind_As_Struct_But_Resolve_By_Interface(t *testing.T) { + instance := container.New() + + err := instance.Singleton(func() *Circle { + return &Circle{a: 13} + }) + assert.NoError(t, err) + + err = instance.Call(func(s Shape) { + a := s.GetArea() + assert.Equal(t, 13, a) + s.SetArea(666) + }) + assert.NoError(t, err) + + err = instance.Call(func(s ReadOnlyShape) { + a := s.GetArea() + assert.Equal(t, 666, a) + }) + assert.NoError(t, err) +} + func TestContainer_SingletonLazy(t *testing.T) { err := instance.SingletonLazy(func() Shape { return &Circle{a: 13}