preface

Hello, guys, I’m Asong. Today, we talk about the magic function init in Go language. Why is it called magic function? Because this function can be called before all program execution begins, and there can be multiple init functions under each package. This function is relatively simple to use, but do you know the order in which it is executed? This article we will decrypt together.

initProperties of a function

Here are some basic features of the init function:

  • init Function beforemainFunction automatic execution
  • There can be more than one in each packageinitFunction, there can also be more than one source file in each packageinitfunction
  • initThe function has no input arguments, return values, and is not declared, so it cannot be referenced
  • Different packageinitThe order in which functions are executed depends on the package import dependencies
  • No matter how many times the package is imported,initThe function will only be called once, that is, executed once

initThe order in which functions are executed

I was curious about the order in which the init function was executed when I first learned about it. I googled several articles and they all had the same graph:

The following figure is from the network:

This picture clearly reflects the order in which init functions are loaded:

  • The priority of package loading is the first, and the package loading is carried out recursively
  • The loading sequence of each package is:const > var > initConstants are initialized first, then variables, and finallyinitFunction. For package level variable initialization order,GoThe official documentationGive an example:
var (
	a = c + b  / / = = 9
	b = f()    / / = = 4
	c = f()    / / = = 5
	d = 3      // == 5 after initialization has finished
)

func f(a) int {
	d++
	return d
}
Copy the code

Variables are initialized from front to back in the order they appear. If a variable needs to depend on another variable, the dependent variable is initialized first. So in this example, the initialization order is D -> B -> C -> A.

The diagram above shows the order in which init functions are loaded. Some details are not known, such as the order in which multiple init functions are executed in the current package or the order in which multiple init functions are executed in the current source file. I wanted to write an example to verify one by one, but it was explained in the official documentation of Go, so there was no need to write another example. Let’s directly say the conclusion:

  • If there are multiple packages under the current packageinitFunction, first executed backwards in lexicographical order of the source file name.
  • If more than one file appearsinitFunction is executed from front to back in the order of occurrence.

Here’s a quick summary of the loading order of init functions:

Starting from the current package, if the current package contains multiple dependent package, the first initialization dependence on package, layers of recursive initialization of each package, in each package, according to the source file dictionary sequence once upon a time in the future, each source file, give priority to initialize constants, variables, and finally the init function to initialize, when there is a multiple init function, After each package is loaded, recursively return, and finally initialize the current package!

initFunction usage scenarios

Remember my previous article: Go unlocks the singleton pattern. We can implement the hunger-hungry singleton pattern by using the loading mechanism of the init function.

The init function can be used in a variety of scenarios, such as registering services, initializing connections to databases or various middleware. Go’s standard library also uses init functions in many places, such as the pprof tool we often use, init function, init function, in the init function to register routes:

/ / go / 1.15.7 / libexec/SRC/CMD/trace/pprof. Go
func init(a) {
	http.HandleFunc("/io", serveSVGProfile(pprofByGoroutine(computePprofIO)))
	http.HandleFunc("/block", serveSVGProfile(pprofByGoroutine(computePprofBlock)))
	http.HandleFunc("/syscall", serveSVGProfile(pprofByGoroutine(computePprofSyscall)))
	http.HandleFunc("/sched", serveSVGProfile(pprofByGoroutine(computePprofSched)))

	http.HandleFunc("/regionio", serveSVGProfile(pprofByRegion(computePprofIO)))
	http.HandleFunc("/regionblock", serveSVGProfile(pprofByRegion(computePprofBlock)))
	http.HandleFunc("/regionsyscall", serveSVGProfile(pprofByRegion(computePprofSyscall)))
	http.HandleFunc("/regionsched", serveSVGProfile(pprofByRegion(computePprofSched)))
}
Copy the code

I don’t want to expand too much here, but you can explore more of the standard library methods.

Here’s a final summary of the problems with init:

  • Don’t rely on it when programminginitThe order of
  • There can be more than one source fileinitFunction, the code is relatively long can consider divided into multipleinitfunction
  • Complex logic is not recommendedinitFunction, which increases code complexity and decreases readability
  • ininitIt can also be started in a functiongoroutineThat is, the new one is launched at the same time as the initializationgoroutine, this does not affect the initialization order
  • initFunctions should not depend on anything inmainVariables created in the function becauseinitThe function is executed inmainPre-function
  • initA function that cannot be explicitly called in code and cannot be referred to (assigned to function variables) or a compilation error will occur.
  • Do not import packages with circular dependencies, as this will cause the program to fail to compile
  • GoThe program just wants to use onepackagetheinitExecution, we can use:import _ "test_xxxx"When importing the package, underline itokthe
  • Package level variable initialization,initFunction executes, both of these operations are in the same placegoroutineIs called sequentially, one package at a time

conclusion

Ok, so that’s the end of this article, init function itself is well understood, the purpose of this article is to give you a sense of the order in which it is executed, so that you don’t write bugs in your daily development. I hope this article was helpful and we’ll see you next time!

Quality three even (share, praise, look) are the author continue to create more quality content motivation! I am aasongAnd we’ll see you next time.

We have created a Golang learning and communication group. Welcome to join the group and we will learn and communicate together. Way to join the group: follow the public account [Golang Dreamworks] to obtain. For more learning materials, please go to the official number.

Recommended previous articles:

  • How does the Go language implement reentrant locking?
  • Which of the Go languages do you use to allocate memory, new or make?
  • Source analysis panic and recover, do not understand you hit me!
  • The scene of large face blows caused by empty structures
  • Leaf-segment Distributed ID Generation System (Golang implementation version)
  • Interviewer: What is the result of two nil comparisons?
  • Interviewer: Can you use Go to write some code to determine how the current system is stored?
  • How to smoothly toggle online Elasticsearch index