During initialization of a
.go file, the compiler will execute any
init functions it finds in the file before the main function.
Multiple Init Statements
Unlike all other functions, that can only be declared once, the
init() function can be declared multiple times throughout a package or file. However, multiple
init()s can make it difficult to know which one has priority over the others.
When declaring multiple
init functions within the same file the
init() functions will execute in the order that you encounter them. In Listing 5.2 the four
init functions are executed in the order that they are declared in the file.
If you have multiple
init() declarations in a package in different files, the compiler will run them based on the order in which it loads files.
Given the directory structure in Listing 5.3, if you had an
init() declaration in
b.go, the first
init() to run would be from
a.go. However, if you renamed
b.go would now run first.
Care must be taken if any
init() declarations have an order of precedence when running and exist in different files.
Using init Functions for Side Effects
In Go, it is sometimes required to import a package not for its content, but for the side effects that occur upon importing the package. This often means that there is an
init() statement in the imported code that executes before any of the other code, allowing for the developer to manipulate the state in which their program is starting. This technique is called importing for a side effect.
A common use case for importing for side effects is to register functionality in your code, which lets a package know what part of the code your program needs to use. In the
image package, for example, the
image.Decode function needs to know which format of image it is trying to decode (
gif, etc.) before it can execute. You can accomplish this by first importing a specific program that has an
init() statement side effect.
A program with this code will still compile, but any time we try to decode a
png image, we will get an error.
To fix this, we need to first register the
.png image format for
image.Decode to use. When imported, the
image/png package, which contains the
init() statement in Listing 5.6, will be call and the package will register itself with the
image package as an image format.
In Listing 5.7, we import
image.png package into our application, then the
image.RegisterFormat() function in
image/png will run before any of our code and register the
.png format before we try and use it.
While this use of
import statements and
init functions can be found in numerous places in the standard library, this is considered an anti-pattern in Go and should never be used. Always be explicit in your code.