init functions

November 19, 2024

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 declare init functions, yet the identifier itself is not declared. Thus init 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)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


When package variable initialization order isn't defined

We’re nearing the end of the discussion on package initialization order. Monday should be the last day on that topic, but more on that shortly. Up to now, we’ve been looking at the deterministic order-of-initialization rules.Today’s topic is when that order is not defined. Package initialization … Dependency analysis is performed per package; only references referring to variables, functions, and (non-interface) methods declared in the current package are considered. If other, hidden, data dependencies exists between variables, the initialization order between those variables is unspecified.


Package variable dependency analysis

Today’s section of the spec is a bit dense and technical. But don’t worry, it makes a lot of sense once we get to the end. Package initialization … Dependency analysis does not rely on the actual values of the variables, only on lexical references to them in the source, analyzed transitively. For instance, if a variable x’s initialization expression refers to a function whose body refers to variable y then x depends on y.


Variable declaration across files

Package initialization … The declaration order of variables declared in multiple files is determined by the order in which the files are presented to the compiler: Variables declared in the first file are declared before any of the variables declared in the second file, and so on. To ensure reproducible initialization behavior, build systems are encouraged to present multiple files belonging to the same package in lexical file name order to a compiler.

Get daily content like this in your inbox!

Subscribe