Welcome To Golang By Example

Init function in Go (Golang)

Overview

init() function is a special function that is used to initialize global variables of a package. These functions are executed when the package is initialized. Each of the GO source files in a package can have its own init() function. Whenever you import any package in the program, then on the execution of that program, init functions(if present)  in the GO source files belonging to that imported package are called first. Some points to note about init function

init function is majorly used for the initialization of global variables that cannot be initialized using an initialization expression. For example, it requires a network call to intialize any DB client. Another example could be fetching secret keys on startup. Init function is also used for running anything that only needs to be executed once. Let’s see a simple use case of using an init function. 

Assume you are using redis cache in your application. You want redis client to created during the application first launch. A good place to initialize a redis client is in init() function. Let’s see an example.

Create a module named redisexample and put below files in that module.

go.mod

module redisexample

go 1.14

redis/redis.go

package redis

import (
	"encoding/json"
	"time"

	"github.com/go-redis/redis"
)

type redisClient struct {
	c *redis.Client
}

var (
	client = &redisClient{}
)

func init() {
	c := redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379",
	})

	if err := c.Ping().Err(); err != nil {
		panic("Unable to connect to redis " + err.Error())
	}
	client.c = c
}

func GetKey(key string, src interface{}) error {
	val, err := client.c.Get(key).Result()
	if err == redis.Nil || err != nil {
		return err
	}
	err = json.Unmarshal([]byte(val), &src)
	if err != nil {
		return err
	}
	return nil
}

//SetKey set key
func SetKey(key string, value interface{}, expiration time.Duration) error {
	cacheEntry, err := json.Marshal(value)
	if err != nil {
		return err
	}
	err = client.c.Set(key, cacheEntry, expiration).Err()
	if err != nil {
		return err
	}
	return nil
}

main.go

package main

import (
	"fmt"
	"log"
	"time"

	"redisexample/redis"
)

func main() {
	err := redis.SetKey("a", "b", time.Minute*1)
	if err != nil {
		log.Fatalf("Error: %v", err.Error())
	}

	var value string
	err = redis.GetKey("a", &value)
	if err != nil {
		log.Fatalf("Error: %v", err.Error())
	}

	fmt.Println(value)

}

Output

b

In the above example, we have an init function in the redis.go file. In the init function we initialize the redis global client which is in turn used in the main function in main.go.

Init function in the main package

main package can also contain the init function. The init function will be triggered before the main function

package main

import "fmt"

var sample int

func init() {
	fmt.Println("In Init function")
	sample = 4
}

func main() {
	fmt.Println("Main started")
	fmt.Println(sample)
	fmt.Println("Main Ended")
}

Output

In Init function
Main started
4
Main Ended

In the above program, we have an init function and the main function. In the init function, we initialize the global variable “sample”. Notice the order of execution i.e init function is executed first and then the main function is executed.

Multiple init() function in different source file of same package

init() function is called in all the source files belonging to a package if present. Let’s see an example for it.

learn/math/add.go

package math

import "fmt"

func init(){
	fmt.Println("In add init")
}

func Add(a, b int) int {
	return a + b
}

learn/math/subtract.go

package math

import "fmt"

func init(){
	fmt.Println("In subtract init")
}

func Subtract(a, b int) int {
	return a - b
}

learn/main.go

package main

import (
	"fmt"

	"github.com/learn/math"
)

func main() {
	fmt.Println(math.Add(2, 1))
	fmt.Println(math.Subtract(2, 1))
}

Output

In add init
In subtract init
3
1

Multiple init() function in same source file

There can be multiple init function within same source file.

package main

import "fmt"

var sample int

func init() {
	fmt.Println("Init1")
}

func init() {
	fmt.Println("Init2")
}

func main() {
	fmt.Println("Main started")
	fmt.Println("Main Ended")
}

Output

Init1
Init2
Main started
Main Ended

In above program we have an init function and a main function. In init function we initialize the global variable “sample”. Notice the order of execution i.e init function is executed first and then the main function is executed.

Order of execution of program

Now as we have seen above examples, let’s see the order of execution of a go program.

Note here that package initialization is only done once even if it is imported several times.

For example if main package imports package a and in turn package a imports package b, then below will be the order

Let’s see a program for the same.

go.mod

module sample

go 1.14

sample/b/b1.go

package b

import (
	"fmt"
)

func init() {
	fmt.Println("Init: b1")
}

func TestB() error {
	return nil
}

sample/b/b2.go

package b

import (
	"fmt"
)

func init() {
	fmt.Println("Init: b2")
}

sample/a/a1.go

package a

import (
	"fmt"
	"sample/b"
)

func init() {
	fmt.Println("Init: a1")
}

func TestA() error {
	return b.TestB()
}

sample/a/a2.go

package a

import (
	"fmt"
)

func init() {
	fmt.Println("Init: a2")
}

sample/main.go

package main

import (
	"fmt"
	"sample/a"
)

func init() {
	fmt.Println("Init: main")
}
func main() {
	fmt.Println("Main Function Executing")
	a.TestA()
}

Output

Init: b1
Init: b2
Init: a1
Init: a1
Init: main
Main Function Executing

Notice in above example that init function in source files of package b are run first. Then init function in source files of package a is run and then init function in source file of main package is run. After that main function is run