If you are coming from other languages that are OOP based like C#, then you might wonder what tool you can use in Go to do something similar as the constructor in a class.
The solution to this is the init function. This is a function that can be defined in each source file.
func init() {
// initialization code
}
The function signature tells us that it neither takes any parameters or returns any result, which hints us that it is supposed to produce some kind of side effect. It's is not uncommon to see the expression, importing a side effect, which refers to this. From the The Go Programming Language Specification:
To import a package solely for its side-effects (initialization), use the blank identifier as explicit package name:
import _ "lib/math"
So this function is the home for initializing variables to get a program to its correct state before everything is starting to run.
Lets do some examples.
package main
import "fmt"
var message = "Hello, init"
func init() {
fmt.Println(message)
}
func main() {
fmt.Println("main")
}
This program will produce the following output:
That's pretty straightforward. First the variable message
will be declared and then the init
function will be called, and finally the main
function.
It is also possible to define several init functions in the same source file.
package main
import "fmt"
var first = "Hello, init"
var second = "Hello, again init"
func main() {
fmt.Println("main")
}
func init() {
fmt.Println(first)
}
func init() {
fmt.Println(second)
}
Which product the following output:
The init
functions will be executed in the order they are defined in the source file. Note that I moved both init functions after the main function to just show that they still will be executed before the main function.
So what happens if you have several source files in the same package that is using an init function?
// first.go
package main
import "fmt"
func init() {
fmt.Println("first.go")
}
// main.go
package main
import "fmt"
func init() {
fmt.Println("main.go")
}
func main() {
fmt.Println("main")
}
// z.go
package main
import "fmt"
func init() {
fmt.Println("z.go")
}
The it will execute the init functions based on lexical order of the filenames. Therefore the init in first.go
will be executed first, then the one in main.go
and finally the one in z.go
.
If you browse through the code in the standard packages you will find many cases where the init function has been used. However be careful, side effects can make things harder to understand when reading the code.
Happy hacking!