got

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 26, 2025 License: MIT Imports: 1 Imported by: 0

README

Got

Fluent dependency injection in Go.

Got provides a declarative way of composing dependencies. It integrates nicely with the common constructor patterns in Go applications.

The main advantage of got is removing the need to manually pass references around when instantiating types that depend on one another.

Installation

go get github.com/eriicafes/got

Usage

got has a very small API surface. You typically only need to use two functions from this library.

Create a constructor

Constructor return values are cached the first time they are requested and future calls return the cached value instead of re-running the constructor. See Transient constructors to opt out of caching.

Constructors are global variables with their names prefixed with Get as a convention.

// printer.go
package main

import "github.com/eriicafes/got"

type Printer interface { 
    Print(string) string
}

var GetPrinter = got.Using(func(c *got.Container) Printer {
    return &CapsPrinter{}
})

// CapsPrinter is an implementation of Printer interface
type CapsPrinter struct{}

func (*CapsPrinter) Print(s string) string { 
    return strings.ToUpper(s)
}
Use in another constructor

Retrieve an instance from a constructor by calling GetXXX.From(container)

// office.go
package main

import "github.com/eriicafes/got"

type Office struct {
    Printer Printer
}

var GetOffice = got.Using(func(c *got.Container) *Office {
    return &Office{
        Printer: GetPrinter.From(c),
    }
})
Use in application

Create a container to hold cached instances.

When calling a constructor, any dependencies it has will also be cached, ensuring that shared dependencies use the same instance.

// main.go
package main

import "github.com/eriicafes/got"

func main() {
    c := got.New()

    office := GetOffice.From(c)
    // or using the From function from got
    office := got.From(c, GetOffice)

    office.Printer.Print()
}

Transient constructors

Transient constructors create a new instance each time it is requested.

If you want your constructor to act as a transient, use GetXXX.New(container) to opt out of caching its return value.

// office.go
package main

import "github.com/eriicafes/got"

type Office struct {
    Printer Printer
}

var GetOffice = got.Using(func(c *got.Container) *Office {
    return &Office{
        // a new printer is created each time
        Printer: GetPrinter.New(c),
    }
})

Multiple return value constructors

Constructors may return two values, for example an instance and an error. Use got.Using2 to create such a constructor.

// bad_office.go
package main

import "github.com/eriicafes/got"

var GetBadOffice = got.Using2(func(c *got.Container) (*Office, error) {
    return nil, fmt.Errorf("failed to create office")
})

Mocking

You can mock a constructor using got.Mock or got.Mock2.

// main.go
package main

import "github.com/eriicafes/got"

type MockPrinter struct{}

var GetMockPrinter = got.Using(func(c *got.Container) Printer {
    return &MockPrinter{}
})

func (*MockPrinter) Print(s string) string {
    return fmt.Sprintf("mocked %s", s)
}

func main() {
    mc := got.New()
    got.Mock(mc, GetPrinter, GetMockPrinter.New(mc))
    office := GetOffice.From(mc)

    office.Printer.Print()
}

Circular dependency errors

Go prevents you from creating circular dependencies as long as you maintain the convention and use global vars as constructors.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func From

func From[T any](c *Container, ct Constructor[T]) T

From returns an instance of a constructor's value from the container. The constructor's New method is called the first time and the return value is cached. Future calls will return the cached value.

func From2

func From2[T, U any](c *Container, ct Constructor2[T, U]) (T, U)

From2 returns an instance of a constructor's value from the container. The constructor's New method is called the first time and the return values are cached. Future calls will return the cached values.

func Mock added in v0.2.0

func Mock[T any](c *Container, ct Constructor[T], v T)

Mock modifies the container cache to return a mocked instance for the constructor.

func Mock2 added in v0.2.0

func Mock2[T, U any](c *Container, ct Constructor2[T, U], v1 T, v2 U)

Mock2 modifies the container cache to return a mocked instance for the constructor.

Types

type Constructor

type Constructor[T any] interface {
	New(*Container) T
	From(*Container) T
}

Constructor is implemented by any type that has a New method that accepts a container and returns a value, and a convenience From method that accepts a container and returns the value from the container.

Use Using to create a new Constructor.

func Using

func Using[T any](fn func(*Container) T) Constructor[T]

Using creates a new Constructor from a function that accepts a container and returns a value.

type Constructor2

type Constructor2[T, U any] interface {
	New(*Container) (T, U)
	From(*Container) (T, U)
}

Constructor2 is implemented by any type that has a New method that accepts a container and returns two values, and a convenience From method that accepts a container and returns the values from the container.

Use Using2 to create a new Constructor2.

func Using2

func Using2[T, U any](fn func(*Container) (T, U)) Constructor2[T, U]

Using2 creates a new Constructor2 from a function that accepts a container and returns two values.

Use Using2 when a constructor returns multiple values for example an instance and an error.

type Container

type Container struct {
	// contains filtered or unexported fields
}

Container is a dependency injection container that caches constructor results. It is safe for concurrent use by multiple goroutines.

The zero Container is empty and ready for use.

func New

func New() *Container

New creates a new Container. While the zero value of Container is ready to use, New() is provided for API clarity.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL