go全局变量、init、main执行顺序问题

问题的来源

有许多人习惯在编码的时候在init函数中初始化一些变量;同时,会在全局定义变量通过形如NewStrucFunc()这样的函数初始化,如果该函数中依赖了init函数中的初始化,此时这个先后顺序就特别重要了,如果init函数执行在前,逻辑是没有问题的,如果是全局变量执行在前,在执行NewStrucFunc()函数时,使用的变量就是未init函数经初始化的,就会有问题,那么答案究竟是什么呢?

设计实验工程

1、简单的在一个main.go文件中

package main

import "fmt"

var var01 = test01()

var var02 = test02()

func test01() int  {
fmt.Println("var-01")
return 1
}

func test02() int {
fmt.Println("var-02")
return 2
}

func init()  {
fmt.Println("init-01")
}

func init()  {
fmt.Println("init-02")
}

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

输出:

➜  test_main_init_var go run main.go
var-01
var-02
init-01
init-02
step main

结论:

在一个go文件中按照声明顺序,依次初始化多个全局变量和 init 函数。

2、如果涉及多个package的import,import包文件中初始化顺序是如何的呢?

main.go文件:

package main

import (
"fmt"

   "test_main_init_var/pkg02"

   "test_main_init_var/pkg01"

)

var var01 = test01()

var var02 = test02()

func test01() int {
fmt.Println("main-var-01")
return 1
}

func test02() int {
fmt.Println("main-var-02")
return 2
}

func init() {
fmt.Println("main-init-01")
}

func init() {
fmt.Println("main-init-02")
}

func main() {
fmt.Println("step main")
pkg01.Action()
pkg02.Action()
}

pkg01.go文件

package pkg01

import "fmt"

var var01 = test01()

var var02 = test02()

func test01() int  {
fmt.Println("pkg01-var-01")
return 1
}

func test02() int {
fmt.Println("pkg01-var-02")
return 2
}

func init()  {
fmt.Println("pkg01-init-01")
}

func init()  {
fmt.Println("pkg01-init-02")
}

func Action()  {
fmt.Println("pkg01-action")
}

pkg02.go文件:

package pkg02

import "fmt"

var var01 = test01()

var var02 = test02()

func test01() int  {
fmt.Println("pkg02-var-01")
return 1
}

func test02() int {
fmt.Println("pkg02-var-02")
return 2
}

func init()  {
fmt.Println("pkg02-init-01")
}

func init()  {
fmt.Println("pkg02-init-02")
}

func Action()  {
fmt.Println("pkg02-action")
}

这个时候的输出:

➜  test_main_init_var go run main.go
pkg02-var-01
pkg02-var-02
pkg02-init-01
pkg02-init-02
pkg01-var-01
pkg01-var-02
pkg01-init-01
pkg01-init-02
main-var-01
main-var-02
main-init-01
main-init-02
step main
pkg01-action
pkg02-action

假如我们互main.go中的pkg01和pkg02的import顺序:

package main

import (
"fmt"

   "test_main_init_var/pkg01"

   "test_main_init_var/pkg02"

)

这是的输出:

➜  test_main_init_var go run main.go
pkg01-var-01
pkg01-var-02
pkg01-init-01
pkg01-init-02
pkg02-var-01
pkg02-var-02
pkg02-init-01
pkg02-init-02
main-var-01
main-var-02
main-init-01
main-init-02
step main
pkg01-action
pkg02-action

结论:很显然,多个package的初始化顺序是根据在main中import的顺序决定。

结论

1、全局变量 > init > main;

2、多package中多个全局变量,多个init 它们内部相对顺序:多根据在main中import的顺序决定,先import的先执行该package下面的(全局变量>init)