I know that golang allows multiple init in one package and even in one file. I am wondering why? For example, if a pkg has many files, we could write multiple init then we could get lost in where to we should put init, and we could be also confused about the init order if we have multiple init in one pkg. (I mean is this better? we can only have 1 init, then we can have some initXXX, then put them into init, it seems quite clean.) What's the advantage of doing this in code struct view?
Golang init() In Go, init() is a very special function meant to execute prior to the main() function. Unlike main(), there can be more than one init() function in a single or multiple files.
It is possible to define multiple init() functions in a file or within the package. The order of execution will be decided as the order of declaration of init() functions.
Init functions are called only once, after all the variable declarations and before the main function. It allows you to initialize whatever your program needs before running.
The INIT function initializes the data structures required by the rest of the computation of the aggregate. For example, if you write a C function, the INIT function can set up large objects or temporary files for storing intermediate results.
This question may be somewhat opinion based, but using multiple package init()
functions can make your code easier to read and maintain.
If your source files are large, usually you arrange their content (e.g. types, variable declarations, methods etc.) in some logical order. Allowance of multiple init()
functions gives you the possibility to put initialization code near to the parts they ought to initialize. If this would not be allowed, you would be forced to use a single init()
function per package, and put everything in it, far from the variables they need to initialize.
Yes, having multiple init()
functions may require some care regarding the execution order, but know that using multiple init()
functions is not a requirement, it's just a possibility. And you can write init()
functions to not have "side" effects, to not rely on the completion of other init()
functions.
If that is unavoidable, you can create one "master" init()
which explicitly controls the order of other, "child" init()
functions.
An example of a "master" init()
controlling other initialization functions:
func init() {
initA()
initB()
}
func initA() {}
func initB() {}
In the above example, initA()
will always run before initB()
.
Relevant section from spec: Package initialization.
Also see related question: What does lexical file name order mean?
Another use case for multiple init()
functions is adding functionality based on build tags. The init()
function can be used to add hooks into the existing package and extend its functionality.
The following is a condensed example demonstrating the addition of more commands to a CLI utility based on build tags.
package main
import "github.com/spf13/cobra"
var rootCmd = &cobra.Command{Use: "foo", Short: "foo"}
func init() {
rootCmd.AddCommand(
&cobra.Command{Use: "CMD1", Short: "Command1"},
&cobra.Command{Use: "CMD2", Short: "Command2"},
)
}
func main() {
rootCmd.Execute()
}
The above is the "vanilla" version of the utility.
// +build debugcommands
package main
import "github.com/spf13/cobra"
func init() {
rootCmd.AddCommand(&cobra.Command{Use: "DEBUG-CMD1", Short: "Debug command1"})
}
The contents of the second file extends the standard command with additional commands that are mostly relevant during development.
Compiling using go build -tags debugcommands
will produce a binary with the added commands, while omitting the -tags
flag will produce a standard version.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With