2020-10-15
Go packages can have more than one init()
function
Go has some surprisingly complex rules for how packages
are initialized, partly because package level variables can be
initialized based on the value returned from function and method
calls (and then other variables can be initialized from them). As
part of package initialization, you can have an initialization
function, called init()
, that will be called.
Or at least that's what I would have told you before I actually had
a reason to read that section of the Go language specification
today. In fact, the specification is very clear that you can have
more than one init()
function in a single package:
Variables may also be initialized using functions named
init
declared in the package block, with no arguments and no result parameters.
func init() { … }
Multiple such functions may be defined per package, even within a single source file. [...]
(Emphasis mine. Package initialization then has details
on what order these init
functions are run in.)
At first this surprised me, but once I thought more it makes sense. On a practical engineering level, it means that you don't have to jam all initialization in a package into a single function in a single file that everyone has to touch; you can spread it out in small pieces wherever is logical and clear.
(You do have to keep track of it all, and the order that functions
in different files get run in depends on how they're built and
linked. The Package initialization section has some suggestions
about that down at the bottom, which you probably don't have to worry
about if you build things with plain usage of go
since it should do
it right for you.)
Because I was curious, I scanned the Go source tree itself to see
if anything used multiple init
functions, especially in the same
file. There is definitely a decent amount of usage of this within
the same package, and even a few cases in the same file (for example,
in cmd/go/main.go).
Unsurprisingly, the runtime
package is a big user of this, since
it covers a lot of functionality; a lot of files in src/runtime
have their own init
functions to cover their specific concerns.
(However the champion user of init
functions is
cmd/compile/internal/ssa/gen.)