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包中的全局变量Value1和Value2的初始化。接着会进行package2包中的init()函数的初始化。在完成package2包的初始化以后,会返回package1包中进行package1包中的初始化。同样的,会先初始化包变量,然后初始化init()函数,完成了两个包的初始化以后,在main函数中一样先初始化包变量,然后初始化init()函数。
总结
综上所述,Go应用程序的初始化顺序可以总结以下几点:
- Go程序初始化时,按照导入包的层次,最先被依赖的包最先被初始化,且初始化的顺序时先初始化包变量,然后初始化
init()函数。 - 一个包内可以有多个
init()函数,每个文件也可以有多个init()函数,多个init()函数按照它们的文件名顺序逐个初始化。 - 应用初始化时的初始化工作顺序是:从被导入的最深层次的包开始进行初始化,层层递出到
main包。 - 不管包被导入多少次,包内的
init()函数只会执行一次。 - 应用在所有的初始化工作完成之后才会执行
main函数。