-
Notifications
You must be signed in to change notification settings - Fork 0
Resolution
Resolve(target any) error // *target = the one match
ResolveAll(target any) error // append every matchtarget must be a pointer. Anything else is ErrInvalidTarget.
var db *Database
if err := c.Resolve(&db); err != nil { ... }The pointed-to type is the request. &db where db is *Database asks for
*Database; &log where log is a Logger interface asks for something
assignable to Logger.
Requesting an interface matches any registered concrete type that implements it. Requesting a concrete type matches only that exact type.
type Logger interface{ Log(string) }
c.Instance(&ConsoleLogger{}) // registers *ConsoleLogger
var l Logger
_ = c.Resolve(&l) // matches *ConsoleLoggerIf more than one registration satisfies the requested interface, resolution
fails with ErrAmbiguousResolution, and the message names every
candidate.
This is deliberate, and it is not fussiness. Registrations live in a map, and Go randomises map iteration order — so "return the first match" would resolve a different implementation on each process start. With two loggers registered, which one a binary used would change from boot to boot, and the bug would reproduce roughly half the time.
Fix it by registering one, or by resolving the concrete type:
var l *ConsoleLogger
_ = c.Resolve(&l) // unambiguous — exact typetarget must be a pointer to a slice of interfaces. Every registration
assignable to the element type is appended.
var checks []HealthCheck
if err := scope.ResolveAll(&checks); err != nil { ... }Where you call it changes what you get:
| Called on | Covers | Cleanup |
|---|---|---|
| the root container | singletons and transients | nothing scoped is built |
a Scope
|
singletons, transients and scoped | scoped values are tracked and closed by Close
|
Scoped registrations are skipped at the root for the same reason Resolve
refuses them: a scoped value built from the root would have no owner. Called on
a scope, anything scoped that ResolveAll constructs is registered with that
scope, so Close releases it — earlier versions built those values and dropped
them on the floor, leaking every closer ResolveAll ever touched.
-
No cycles are detected.
AneedingBneedingArecurses until the stack is exhausted. See Limitations. -
No partial construction. A factory that panics propagates the panic to
the caller of
Resolve; nothing is memoised. -
No names or tags. The Go type is the only key. Two
*sql.DBvalues that mean different things need two types (type ReadDB struct{ *sql.DB }), not two names.
dix — Dependency Injection eXperience · MIT · © 2026 Kryovyx · pre-1.0, interfaces may change
Concepts
Reference
Practice
Ecosystem