乐闻世界logo
搜索文章和话题

When is the init function run on golang

5个答案

1
2
3
4
5

The init function in Go has special significance. It is automatically executed after the package-level variables are initialized, but before any other function is called. Specifically, the execution timing of the init function is as follows:

  1. When a package is imported, the Go compiler first checks if it has been initialized. If not, it initializes the dependencies of the package.
  2. Then, after the package-level variables are initialized, the init function for the package is called. This process is automatic and determined at compile time.
  3. If a package has multiple init functions (which may be scattered across multiple files in the package), they are called in the order they appear in the code.
  4. If a package is imported by multiple other packages, its init function is executed only once.

This mechanism ensures that the init function runs only once, regardless of how many times the package is imported, and before the main function of the program runs. This design is used for performing initialization tasks such as setting up internal data structures of the package, initializing variables, or registering necessary information.

For example, if there is a database package, you might set up the database connection pool in the init function:

go
package database import "database/sql" var dbPool *sql.DB func init() { var err error dbPool, err = sql.Open("postgres", "connection_string") if err != nil { log.Fatalf("Database connection failed: %s", err) } } // Other database operation functions...

In this example, regardless of how many times the database package is imported or where it is imported in the program, the init function ensures that the database connection is set up before any database operations are performed.

2024年6月29日 12:07 回复

This is another example - https://play.golang.org/p/9P-LmSkUMKY

go
package main import ( "fmt" ) func callOut() int { fmt.Println("Outside is executed") return 1 } var test = callOut() func init() { fmt.Println("Init3 is executed") } func init() { fmt.Println("Init is executed") } func init() { fmt.Println("Init2 is executed") } func main() { fmt.Println("Doing your thing!") }

The output of the above program

$ go run init/init.go Outside is executed Init3 is executed Init is executed Init2 is executed Doing your thing!

2024年6月29日 12:07 回复

This requires additional content (I will add it as a comment, but at the time of writing this article, I did not have sufficient reputation).

When there are multiple init functions in the same package, I have not found any guaranteed way to know their execution order. For example, I have:

go
package config - config.go - router.go

Both config.go and router.go contain init() functions, but when running router.go, the init() function executes first (which causes my application to panic).

If you have multiple files, each with its own init() function, please note that you cannot guarantee that one file runs before another. It's better to use variable assignments, as demonstrated by OneToOne in his example. The best part is: this variable declaration occurs before all init() functions in the package.

Example:

go
// config.go var ConfigSuccess = configureApplication() func init() { doSomething() } func configureApplication() bool { l4g.Info("Configuring application...") if valid := loadCommandLineFlags(); !valid { l4g.Critical("Failed to load Command Line Flags") return false } return true }
go
// router.go func init() { var ( rwd string tmp string ok bool ) if metapath, ok := Config["fs"]["metapath"].(string); ok { var err error Conn, err = services.NewConnection(metapath + "/metadata.db") if err != nil { panic(err) } } }

Regardless of whether var ConfigSuccess = configureApplication() exists in router.go or config.go, it will run before any init() function.

2024年6月29日 12:07 回复

Look at this image. :) import → const → var → init()

  1. If a package imports other packages, it first initializes the imported packages.
  2. Then it initializes the constants of the current package.
  3. Then it initializes the variables of the current package.
  4. Finally, init() calls the functions of the current package.

A package can have multiple init functions (defined in a single file or across multiple files), and they are invoked in the order they appear to the compiler. Even when imported from multiple packages, a package is initialized only once.

2024年6月29日 12:07 回复

Yes, consider this example: [http://play.golang.org/p/dvHymTy73F]

go
var WhatIsThe = AnswerToLife() func AnswerToLife() int { // 1 return 42 } func init() { // 2 WhatIsThe = 0 } func main() { // 3 if WhatIsThe == 0 { fmt.Println("It's all a lie.") } }

AnswerToLife() is guaranteed to run before init() is called, and init() is guaranteed to run before main() is called.

Remember that init() is always called regardless of whether main is present; therefore, if you import a package containing an init function, it will be executed.

Additionally, each package can have multiple init() functions; they execute in the order they appear in the file (obviously after all variable initialization).

If they span multiple files, they execute in lexicographical file name order (as pointed out by @benc).

The function seems to execute in lexicographical file name order. The Go specification states that 'build systems are encouraged to present multiple files belonging to the same package to the compiler in lexicographical file name order.' This appears to be the case with tools like go build.

Many internal Go packages use init() for initializing tables, for example, [https://github.com/golang/go/blob/883bc6/src/compress/bzip2/bzip2.go#L480]

2024年6月29日 12:07 回复

你的答案