Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the purpose of golang allowing multiple init in one package?

Tags:

go

init

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?

like image 400
harrycmfan Avatar asked Jul 24 '17 10:07

harrycmfan


People also ask

What is the use of init function in Golang?

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.

Can you define multiple init () functions in the same .Go file?

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.

Is INIT called only once?

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.

What is an init function?

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.


2 Answers

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?

like image 143
icza Avatar answered Sep 22 '22 12:09

icza


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.

like image 29
Henrik Aasted Sørensen Avatar answered Sep 20 '22 12:09

Henrik Aasted Sørensen