Dependency injection gives a function or component its dependencies from outside instead of constructing them internally. A money converter can receive an exchange-rate provider while remaining unaware of the bank, API, or data source behind it. This separates fetching from conversion, reduces assumptions, and makes replacement and testing easier. section 6.5 section 10.8
Go supports two common dependency-injection forms:
- Interface dependency: pass an object implementing a small interface, such as a ratesFetcher with FetchRates(from, to). section 6.5.1
- Function dependency: pass a function with the required signature, optionally naming that signature as a type. section 6.5.1
- Local functions can provide configuration-specific behavior, while separate fetchers can support free or authenticated rates. section 6.5.1
- Small interfaces close to their use restrict what a dependency can do and let tests substitute mocks instead of hardcoded implementations. section 10.3.3 section 10.8
Injecting a repository
A habits service can receive a Repository through its constructor, while its Create function accepts a smaller habitCreator interface. The main function supplies the real repository; tests supply a mock that implements only Add. The service therefore validates and saves habits without constructing or depending directly on the repository implementation. section 10.3.3
Listing 6.34 Dependency injection via an interface
type ratesFetcher interface {
FetchRates(from, to Currency) (ExchangeRate, error) #1
}
func Convert(..., rates ratesFetcher) { #2
...
rate, err := rates.FetchRates(from, to) #2
...
}
...
func main() {
ratesRepo := newRatesRepository() #3
money.Convert(..., ratesRepo)
}
Use the interface-based listing to see the contract, injected parameter, and caller-created implementation in one compact Go example. section 6.5.1
Listing 6.35 Dependency injection via a function
func Convert(...,
rates func(from Currency, #1
to Currency) (ExchangeRate, error), #1
) (Amount, error) {
...
rate, err := rates(from, to) #2
...
}
func main() {
ratesRepo := newRatesRepository() #3
money.Convert(..., ratesRepo.FetchRates) #4
}
Compare the function-based form, where Convert receives ratesRepo.FetchRates directly rather than an object implementing an interface. section 6.5.1




















