golang 多个 init 方法的执行顺序
目录结构:
> # cd /data/init
> # tree
.
├── a
│ └── a.go
├── b
│ └── b.go
├── go.mod
└── main.go
2 directories, 4 files
a/a.go
package aimport ( "fmt" "path/filepath")func init() { fmt.Println("a init") dir, _ := filepath.Abs("./") // 这里的路径是以 import 导入时执行为准 fmt.Println(dir)}func Add() { fmt.Println("a Add")}
b/b.go
package bimport ( "fmt" "path/filepath")func init() { fmt.Println("b init") dir, _ := filepath.Abs("./") // 这里的路径是以 import 导入时执行为准 fmt.Println(dir)}func Add() { fmt.Println("b Add")}
main.go
package mainimport ( "fmt" "init/a" // 导入包的顺序 决定了 init() 函数谁先执行 "init/b")func init() { fmt.Println("main init 1")}func init() { fmt.Println("main init 2")}func main() { fmt.Println("main") a.Add() b.Add()}
> # go run main.go
a init
/data/init
b init
/data/init
main init 1
main init 2
main
a Add
b Add
现在调整导入包的顺序
main.go
package mainimport ( "fmt" "init/b" // 导入包的顺序 决定了 init() 函数谁先执行 "init/a")func init() { fmt.Println("main init 1")}func init() { fmt.Println("main init 2")}func main() { fmt.Println("main") a.Add() b.Add()}
> # go run main.go
b init
/data/init
a init
/data/init
main init 1
main init 2
main
a Add
b Add
结论:
可以看出init()函数执行顺序是按照导入包的顺序执行, 而不是按照调用先后顺序执行。
init 函数的主要作用:初始化。
init 函数的主要特点:
init 函数先于 main 函数自动执行, 不能被其他函数调用;
init 函数没有输入参数、返回值;
每个包可以有多个 init 函数;
包的每个源文件也可以有多个 init 函数, 这点比较特殊;
同一个包的 init 执行顺序, golang 没有明确定义, 编程时要注意程序不要依赖这个执行顺序。
不同包的 init 函数按照包导入的依赖关系决定执行顺序。
注意: golang 使用路径时尽量使用绝对路径, 避免不必要的错误