What does this print? Explain Go's package initialization order.
Question 435HardGo 1.22 to 1.25
package main
import "fmt"
var a = b + 1
var b = f()
func f() int { fmt.Println("f"); return 1 }
func init() { fmt.Println("init1", a, b) }
func init() { fmt.Println("init2") }
func main() { fmt.Println("main") }
Output:
f
init1 2 1
init2
main
The rules:
- Imported packages are initialized first, depth-first, and each package exactly once, however many packages import it. Since Go 1.21 the order among independent imports is defined: packages are sorted by import path, and a package is initialized once all its dependencies are.
- Inside a package, package-level variables are initialized in dependency order, not source order.
adepends onb, sob = f()runs first even though it is declared later. Variables with no dependencies are initialized in declaration order, across files in the order they are given to the compiler (sorted by filename). - Then every
init()runs in source order. A package can have many of them, even several in one file, and they cannot be called or referenced. - Finally
main.mainruns. All of initialization runs in a single goroutine.
Gotchas: an initialization cycle (var x = y; var y = x) is a compile error. Heavy init() work such as network calls, flag parsing or panics hurts testability and startup time. Blank imports (_ "image/png", database drivers) exist only to trigger init registration.
More on Modules, Packages & Tooling
- Q433How does //go:embed work? Show the three target types.
- Q434What are the gotchas of go:embed patterns? Why is my .env or _redirects file missing?
- Q436Go forbids import cycles. How do you detect and break them?
- Q437A vulnerable dependency shows up in your build. How do you find out why it's there and upgrade it safely?
- Q438What is Profile-Guided Optimization (PGO) in Go and how do you use it in production?
- Q439How does Go ship behavior changes without breaking old code? Explain GODEBUG, the godebug directive and //go:debug. What does this print?