Documentation
¶
Index ¶
- Variables
- func IsInputTypeAllowed(typ reflect.Type) bool
- func IsOutputTypeAllowed(typ reflect.Type) bool
- func IsTypeAllowed(typ reflect.Type) bool
- func MustResolve[T any](inj interface{ ... }) T
- func MustResolveContext[T any](ctx context.Context, inj interface{ ... }) T
- func Resolve[T any](inj interface{ ... }) (T, error)
- func ResolveContext[T any](ctx context.Context, inj interface{ ... }) (T, error)
- type Element
- type Injector
- func (inj *Injector) Apply(val any) error
- func (inj *Injector) ApplyContext(ctx context.Context, val any) error
- func (inj *Injector) Build(ctors ...any) error
- func (inj *Injector) BuildContext(ctx context.Context, ctors ...any) error
- func (inj *Injector) Invoke(f any) ([]any, error)
- func (inj *Injector) InvokeContext(ctx context.Context, f any) ([]any, error)
- func (inj *Injector) Provide(ctors ...any) (xerr error)
- func (inj *Injector) Resolve(refs ...any) error
- func (inj *Injector) ResolveContext(ctx context.Context, refs ...any) error
- func (inj *Injector) SetParent(parent *Injector) error
- type Resolver
- type Slice
- type Void
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrTypeNotProvided = errors.New("type not provided") ErrTypeAlreadyProvided = errors.New("type already provided") ErrParentAlreadySet = errors.New("parent already set") ErrTypeNotAllowed = errors.New("type not allowed") ErrCircularDependency = errors.New("circular dependency detected") ErrErrorTypeMustBeLast = errors.New("error type must be the last return value") ErrInvalidProvider = errors.New("provide only accepts a function that returns at least one type except error") ErrInvalidInvokeTarget = errors.New("invoke only accepts a function") ErrInvalidApplyTarget = errors.New("apply only accepts a struct") )
var ( TagName = "inject" TagValueOptional = "optional" )
Functions ¶
func IsInputTypeAllowed ¶ added in v1.1.2
IsInputTypeAllowed checks if a type is allowed as a function input parameter. Element[T] types are not allowed as input - use Slice[T] instead.
func IsOutputTypeAllowed ¶ added in v1.1.2
IsOutputTypeAllowed checks if a type is allowed as a function output. Slice[T] types are not allowed as output - use Element[T] instead.
func IsTypeAllowed ¶ added in v1.0.0
IsTypeAllowed checks if a type is allowed as a function input or output parameter.
func MustResolve ¶ added in v1.0.0
MustResolve resolves a dependency from the injector.
func MustResolveContext ¶ added in v1.0.0
Types ¶
type Element ¶ added in v1.1.2
type Element[T any] struct { Value T }
Element is a wrapper type that allows multiple values of the same type T to be provided to the injector. When resolving Slice[T], all *Element[T] values will be collected and returned.
Usage:
inj.Provide(func() *Element[http.Handler] { return NewElement(handler1) })
inj.Provide(func() *Element[http.Handler] { return NewElement(handler2) })
// Resolve as Slice[T]
var handlers Slice[http.Handler]
inj.Resolve(&handlers) // handlers = []http.Handler{handler1, handler2}
func NewElement ¶ added in v1.1.2
NewElement creates a new *Element[T] with the given value.
func NewVoidElement ¶ added in v1.2.0
NewVoidElement creates a new *Element[*Void].
type Injector ¶
type Injector struct {
// contains filtered or unexported fields
}
Example ¶
package main
import (
"fmt"
"github.com/theplant/inject"
)
// Define interfaces and implementations
type Printer interface {
Print() string
}
type SimplePrinter struct{}
func (p *SimplePrinter) Print() string {
return "Printing document"
}
// New type definition
type DocumentDescription string
type Document struct {
Injector *inject.Injector `inject:""`
ID string
Description DocumentDescription `inject:""`
Printer Printer `inject:""`
Size int64 `inject:"optional"`
page int `inject:""`
name string `inject:"optional"`
ReadCount int32 `inject:""`
}
func main() {
inj := inject.New()
// Provide dependencies
if err := inj.Provide(
func() Printer {
return &SimplePrinter{}
},
func() string {
return "A simple string"
},
func() DocumentDescription {
return "A document description"
},
func() (int, int32) {
return 42, 32
},
); err != nil {
panic(err)
}
{
// Resolve dependencies
var printer Printer
if err := inj.Resolve(&printer); err != nil {
panic(err)
}
fmt.Println("Resolved printer:", printer.Print())
}
printDoc := func(doc *Document) {
fmt.Printf("Document id: %q\n", doc.ID)
fmt.Printf("Document description: %q\n", doc.Description)
fmt.Printf("Document printer: %q\n", doc.Printer.Print())
fmt.Printf("Document size: %d\n", doc.Size)
fmt.Printf("Document page: %d\n", doc.page)
fmt.Printf("Document name: %q\n", doc.name)
fmt.Printf("Document read count: %d\n", doc.ReadCount)
}
fmt.Println("-------")
{
// Invoke a function
results, err := inj.Invoke(func(printer Printer) *Document {
return &Document{
// This value will be retained as it is not tagged with `inject`, despite string being provided
ID: "idInvoked",
// This value will be overridden since it is tagged with `inject` and DocumentDescription is provided
Description: "DescriptionInvoked",
// This value will be overridden with the same value since it is tagged with `inject` and Printer is provided
Printer: printer,
// This value will be retained since it is tagged with `inject:"optional"` and int64 is not provided
Size: 100,
}
})
if err != nil {
panic(err)
}
printDoc(results[0].(*Document))
}
fmt.Println("-------")
{
// Apply dependencies to a struct instance
doc := &Document{}
if err := inj.Apply(doc); err != nil {
panic(err)
}
printDoc(doc)
}
fmt.Println("-------")
{
// Create a child injector and then apply dependencies to a struct instance
child := inject.New()
_ = child.SetParent(inj)
doc := &Document{}
if err := child.Apply(doc); err != nil {
panic(err)
}
printDoc(doc)
}
}
Output: Resolved printer: Printing document ------- Document id: "idInvoked" Document description: "A document description" Document printer: "Printing document" Document size: 100 Document page: 42 Document name: "A simple string" Document read count: 32 ------- Document id: "" Document description: "A document description" Document printer: "Printing document" Document size: 0 Document page: 42 Document name: "A simple string" Document read count: 32 ------- Document id: "" Document description: "A document description" Document printer: "Printing document" Document size: 0 Document page: 42 Document name: "A simple string" Document read count: 32
func (*Injector) ApplyContext ¶ added in v1.0.0
func (*Injector) Build ¶ added in v1.0.0
Build automatically resolves all provided types using background context. This will trigger the creation of all registered constructors, ensuring that all dependencies are properly instantiated.
Example ¶
ExampleInjector_Build demonstrates eager dependency building. The Build and BuildContext methods allow you to eagerly instantiate all provided dependencies at once. This is useful for: - Application startup initialization - Validating that all dependencies can be created successfully - Pre-warming expensive dependencies - Ensuring deterministic dependency creation order
package main
import (
"fmt"
"github.com/theplant/inject"
)
// Define interfaces and implementations
type Printer interface {
Print() string
}
type SimplePrinter struct{}
func (p *SimplePrinter) Print() string {
return "Printing document"
}
func main() {
inj := inject.New()
// Provide dependencies
if err := inj.Provide(
func() string { return "config-value" },
func() int { return 42 },
func(s string) Printer {
fmt.Printf("Creating printer with config: %s\n", s)
return &SimplePrinter{}
},
); err != nil {
panic(err)
}
// Build all dependencies eagerly
if err := inj.Build(); err != nil {
panic(err)
}
fmt.Println("All dependencies built successfully!")
// All dependencies are now instantiated and ready to use
var printer Printer
if err := inj.Resolve(&printer); err != nil {
panic(err)
}
fmt.Println("Resolved printer:", printer.Print())
}
Output: Creating printer with config: config-value All dependencies built successfully! Resolved printer: Printing document
func (*Injector) BuildContext ¶ added in v1.0.0
BuildContext automatically resolves all provided types. This will trigger the creation of all registered constructors, ensuring that all dependencies are properly instantiated.
func (*Injector) InvokeContext ¶ added in v1.0.0
func (*Injector) ResolveContext ¶ added in v1.0.0
type Resolver ¶ added in v1.2.0
Resolver is an interface for resolving dependencies from an injector.
type Slice ¶ added in v1.1.2
type Slice[T any] []T
Slice is a container type that collects all *Element[T] values into a slice of T. Use Slice[T] to resolve multiple *Element[T] providers at once.
type Void ¶ added in v1.2.0
type Void struct{}
Void is a marker type for constructors that don't return any value. When a constructor has no return type (or only returns error), it is automatically treated as returning *Element[*Void].
This allows "side-effect only" constructors (e.g., modifying config) to be registered and executed through the injection system.
Usage:
// Void constructor - automatically returns *Element[*Void]
inj.Provide(func(cfg *Config) {
cfg.Debug = true // Modify config as side effect
})
// Execute all void constructors via Build
inj.Build()
// Or resolve explicitly
var voids Slice[*Void]
inj.Resolve(&voids)