Package Initialization 包括两部分
- 变量初始化
init()
functions
变量初始化
- Within a package, package-level variable initialization proceeds stepwise, with each step selecting the variable earliest in declaration order which has no dependencies on uninitialized variables.
- More precisely, a package-level variable is considered ready for initialization if it is not yet initialized and either has no initialization expression or its initialization expression has no dependencies on uninitialized variables.
- The declaration order of variables declared in multiple files is determined by the order in which the files are presented to the compiler: Variables declared in the first file are declared before any of the variables declared in the second file, and so on.
Demo
// sw_pprof.go
package main
import (
"fmt"
)
var swV1 = privateF()
var swV2 = privateF2()
func privateF() int {
fmt.Println("call main's privateF")
return 5
}
func privateF2() int {
fmt.Println("call main's privateF2")
return 5
}
func init() {
fmt.Println("call main's init")
}
func main() {}
输出:
call main's privateF
call main's privateF2
call main's init
Within a package, package-level variable initialization proceeds stepwise, with each step selecting the variable earliest in declaration order which has no dependencies on uninitialized variables.
More precisely, a package-level variable is considered ready for initialization if it is not yet initialized and either has no initialization expression or its initialization expression has no dependencies on uninitialized variables. Initialization proceeds by repeatedly initializing the next package-level variable that is earliest in declaration order and ready for initialization, until there are no variables ready for initialization.
For example, given the declarations
package main
import "fmt"
var (
a = c + b // == 9
b = f() // == 4
c = f() // == 5
d = 3 // == 5 after initialization has finished
)
func f() int {
d++
return d
}
func main() {
fmt.Printf("a: %v, b: %v, c: %v, d: %v", a, b, c, d)
}
the initialization order is d
, b
, c
, a
. Note that the order of subexpressions in initialization expressions is irrelevant: a = c + b
and a = b + c
result in the same initialization order in this example.
输出:
a: 9, b: 4, c: 5, d: 5
init()
functions
Variables may also be initialized using init
functions.
func init() { … }
Multiple such functions may be defined. They cannot be called from inside a program.
- A package with
no imports
is initialized- by assigning initial values to all its package-level variables,
- followed by calling all
init()
functions in the order they appear in the file. - If multiple files have
init()
, theseinit()
functions will be called in the order of itslexical file name
- Imported packages are initialized before the package itself.
- Each package is initialized once, regardless if it’s imported by multiple other packages.
It follows that there can be no cyclic dependencies.
Misc:
- Package initialization happens in a single goroutine, sequentially, one package at a time.
- An
init
function may launch other goroutines, which can run concurrently with the initialization code. However, initialization always sequences theinit
functions: it will not invoke the next one until the previous one has returned.
Reference
- https://golang.org/ref/spec#Package_initialization
- https://tutorialedge.net/golang/the-go-init-function/
- https://medium.com/golangspec/init-functions-in-go-eac191b3860a
- https://zhuanlan.zhihu.com/p/34211611
- https://stackoverflow.com/questions/31650965/what-does-lexical-file-name-order-mean
- https://stackoverflow.com/questions/32829538/init-order-within-a-package
- https://yourbasic.org/golang/package-init-function-main-execution-order/
- https://stackoverflow.com/questions/24790175/when-is-the-init-function-run