Go程序如何进行初始化?

72 阅读3分钟

Go应用程序的初始化是在单一的goroutine进行的,对于包的初始化来说,在一个包里会先进行包级别变量的初始化。一个包下可以有多个init函数,每个文件也可以有多个init函数,多个init函数会按照它们的文件名顺序诸葛进行初始化。但是程序不可能把所有的代码都放在一个包里,如果main包引入了pkg1包,pkg1包又引入了pkg2包,那么应用程序的初始化是怎么进行的呢?

我们可以写段代码验证一下。

代码目录如下:

├── main.go
├── package1
│   └── package1.go
├── package2
│   └── package2.go
└── utiles
    └── utiles.go

在utiles包下有utiles1文件:

package utiles

import "fmt"

func InitTest(t string, v int) int {
	fmt.Println("Init Test-------", t, "---------", v)
	return v
}

在package1包下有package1.go文件:

package package1

import (
	"fmt"
	"goStudy/init/package2"
	"goStudy/init/utiles"
)

var V1 = utiles.InitTest("init package1 value1", package2.Value1 + 10)
var V2 = utiles.InitTest("init package2 value2", package2.Value2 + 10)

func init() {
	fmt.Println("init func in package1")
}

在package2包下有package2.go文件:

package package2

import (
	"fmt"
	"goStudy/init/utiles"
)


var Value1 = utiles.InitTest("init package2 value1", 20)
var Value2 = utiles.InitTest("init package2 value2", 10)

 func init() {
	fmt.Println("init func1 in package2")
 }

 func init() {
	fmt.Println("init func2 in package2")
 }

最后是main.go:

package main

import (
	"fmt"
	"goStudy/init/package1"
	"goStudy/init/utiles"
)




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

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

var MainValue1 = utiles.InitTest("init M_v1", package1.V1 + 10)
var MainValue2 = utiles.InitTest("init M_v2", package1.V2 + 10)

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

执行go run main.go,我们得到:

Init Test------- init package2 value1 --------- 20
Init Test------- init package2 value2 --------- 10
init func1 in package2
init func2 in package2
Init Test------- init package1 value1 --------- 30
Init Test------- init package2 value2 --------- 20
init func in package1
Init Test------- init M_v1 --------- 40
Init Test------- init M_v2 --------- 30
init func1 in main
init func2 in main
main func in main

在上面的结果中,我们可以看到,执行main函数的时候会先初始化包,按照引入包的顺序,最先被依赖的包最先被初始化,且初始化的顺序是先初始化包变量,然后初始化init函数。在实际例子中,我们先初始化package1包而在package1包中,我们又先引入了package2包。因此我们先进行package2包中的全局变量Value1Value2的初始化。接着会进行package2包中的init()函数的初始化。在完成package2包的初始化以后,会返回package1包中进行package1包中的初始化。同样的,会先初始化包变量,然后初始化init()函数,完成了两个包的初始化以后,在main函数中一样先初始化包变量,然后初始化init()函数。

总结

综上所述,Go应用程序的初始化顺序可以总结以下几点:

  • Go程序初始化时,按照导入包的层次,最先被依赖的包最先被初始化,且初始化的顺序时先初始化包变量,然后初始化init()函数。
  • 一个包内可以有多个init()函数,每个文件也可以有多个init()函数,多个init()函数按照它们的文件名顺序逐个初始化。
  • 应用初始化时的初始化工作顺序是:从被导入的最深层次的包开始进行初始化,层层递出到main包。
  • 不管包被导入多少次,包内的init()函数只会执行一次。
  • 应用在所有的初始化工作完成之后才会执行main函数。