go学习笔记-init函数执行顺序分析

语言: CN / TW / HK

golang 中有个神奇的函数 init ,该函数会在所有程序执行开始前被调用,每个包可以包含多个 init 函数,所有被编辑器识别到的 init 函数都会在 main 函数执行前被调用。通常被用来注册一个程序需要使用的依赖,如 mysql 注册,配置文件加载等。

在main包的使用

package main
import "fmt"
func main()  {
	fmt.Println("这里是mian")
}
func  init()  {
	fmt.Println("这里是Init1")
}
func  init()  {
	fmt.Println("这里是Init2")
}
//输出结果
这里是Init1
这里是Init2
这里是main

一个很简单的示例,可以看到 init 函数是在main函数执行之前被执行的,并且一个包可以有多个 init 函数

在其他包中使用

  • main包
package main
import (
	"fmt"
	"test/services"
)
func main()  {
	fmt.Println("这里是main")
	services.Run()
}
func  init()  {
	fmt.Println("这里是main init")
}
  • services包
package services
import "fmt"
func Run()  {
	fmt.Println("这里是 services run")
}
func init()  {
	fmt.Println("这里是 services里面的init")
}
  • 结果
这里是 services里面的init
这里是main init
这里是main
这里是 services run

可以看到这里先执行了 services 包里面的 init ,在执行的 maininit 。这是因为在编译的时候会先去检查导入的包,首先发现其他包里面的 init ,然后才会到 main 包里面的init。那如果 services 里面又包含了其他的包呢?其他包里面又在不同的文件中有不的 init 呢?下面我们一起来看看到底 init 的顺序是怎么样的。

多个包嵌套

在上面的基础上增加 third

  • 目录结构
---services
-----service.go
---third
-----third_a.go
-----third_b.go
---main.go
  • third_a.go
package third
import "fmt"
func TestA()  {
}
func init()  {
	fmt.Println("这里是 third  init a")
}
  • third_b.go
package third
import "fmt"
func TestB()  {
}
func init()  {
	fmt.Println("这里是 third  init b")
}
  • serice.go
package services
import (
	"fmt"
	"test/third"
)
func Run()  {
	fmt.Println("这里是 services run")
	third.TestB() // 先调用 testB
	third.TestA() // 在调用 testA
}
func init()  {
	fmt.Println("这里是 services里面的init")
}
  • 结果
这里是 third init a
这里是 third init b
这里是 services里面的init
这里是 main init
这里是 main
这里是 services run

可以看到这里先执行了 third_a 中的 init ,再执行了 third_b 中的 init ,而不是按照我们函数的调用顺序来执行的,那么是按照文件的排序来定的?我觉得应该是这样的,官方只是说按源文件的顺序执行,具体是否是这样只有靠实际实践来看,目前来看是这样的顺序。其实我们大可不必纠结太多的顺序问题。

我们只需要知道,每个包中可以有多个 init 函数,而其他包的 init 是在main包的 init 调用之前被执行, main 函数最后执行即可,如果非要有依赖的顺序关系,那么可以在 init 中 包含调用即可

期待一起交流

分享到: