Initialization

初始化参数

  • golang 程序变量的初始化和变量的初始依赖相关
    • 初始化过程会存在多轮周期,每轮周期只初始化没有任何外部依赖的变量
    • 初始化过程一直持续到全部变量完成初始化
    • 如果依赖关系形成循环,编译器会直接报错(如 initialization cycle)
    • 包级别的初始化在 main 函数执行之前、由主 goroutine 串行完成,因此初始化函数可以安全地使用 goroutine,但被启动的 goroutine 要等初始化全部结束后才会被调度
var (
	a int = b + 1
	b int = 1
)

func main() {
	fmt.Println(a) // 2  第二轮初始化
	fmt.Println(b) // 1  第一轮初始化
}

初始化顺序:第一轮先初始化没有依赖的 b = 1;第二轮再计算依赖 b 的 a = b + 1 = 2。声明顺序在前不代表初始化在前,依赖关系才是决定因素。

init

  • init() 在包函数被执行前以及包内变量初始化后被调用
    • 变量初始化 -> init() -> main()
    • 每个包可以包含多个 init() 函数,同一个文件也可以有多个,按声明顺序执行
  • init 多用于初始化全局变量,先于 main 函数执行,并且不能被其他函数调用
    • init 函数没有传参和返回值,仅用来初始化当前包内的参数
    • init 的执行顺序和包的引入顺序相关:先初始化被导入的包,再执行当前包的 init
  • import _ "net/http/pprof" 表示仅导入包的 init 函数,不使用包内其他导出内容

完整执行顺序可总结为:

导入包的包级变量初始化 -> 导入包的 init() -> (递归向上) -> 当前包变量初始化 -> 当前包 init() -> main()

Example:

  1. 先执行全部变量的初始化
  2. 再执行 init 函数
  3. 最后执行主函数
var T int64 = a()

func init() {
	fmt.Println("init in main.go ")
}

func a() int64 {
	fmt.Println("calling a()")
	return 2
}

func main() {
	fmt.Println("calling main")
}
/**calling a()
init in main.go 
calling main**/

输出印证了顺序:a() 在变量初始化阶段最先被调用(即使它在 init 之后声明),然后是 init,最后才是 main。