We’ve been looking at the order of package variable initialization.
What if these rules are confusing? Or even non-desterministic for you? Or maybe you simply want to do something more advanced than is feasible in package variable declarations. Is there an alternative?
There is!
Package initialization
…
Variables may also be initialized using functions named
init
declared in the package block, with no arguments and no result parameters.func init() { … }
Note that package variables can be initialized, but not declared within an init
function. That’s because any variables declared within an init
function are scoped to that function–just as they are in any other function.
var packageVariable int // Declared, but uninitialized; initial default value is 0
func init() {
var functionVariable int
packageVariable = 3 // Now the package variable has a value of 3
functionVariable = 5 // This variable goes out of scope as soon as `init` exits
}
Multiple such functions may be defined per package, even within a single source file.
Yes, you read that right. You can define multiple init
functions in the same package, or even the same file.
While pointless, this is valid:
func init() {}
func init() {}
func init() {}
func init() {}
And while you’re allowed to have multiple init
functions, it’s probably best not to, except under exceptional circumstances. The ideal number of init
functions is usually 0. But when you really need one, it’s generally best to keep all of your init
functionality together. But if you find a legtimate exception, don’t hold yourself to this advice. 😊
… In the package block, the
init
identifier can be used only to declareinit
functions, yet the identifier itself is not declared. Thusinit
functions cannot be referred to from anywhere in a program.
This means that at package scope, you cannot declare anything using the name init
. These are all invalid:
var init = 3
const init = "Let's Go!"
func init() error { /* ... */}
type init struct { /* ... */ }
However, within a function these can be valid (though highly discouraged):
func main() {
type init struct{}
{ // just to create a new code block
var init init
fmt.Println(init) // Prints: {}
}
}
The entire package is initialized by assigning initial values to all its package-level variables followed by calling all
init
functions in the order they appear in the source, possibly in multiple files, as presented to the compiler.
Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)