深入理解Go语言init方法的执行顺序
作者:liushen0528
一、什么是init方法?
init 是 Go 语言中的特殊函数,无需手动调用,由运行时自动执行。每个 .go 文件可以包含多个 init 函数。init方法没有参数和返回值。
示例代码如下:
func init() { // 初始化逻辑 }
init 函数在 main() 函数之前执行。当包被导入时,系统会自动调用所有 init 函数,其调用顺序为:先执行依赖包(被导入的包)的 init 函数,再执行当前包的 init 函数,最后执行 main() 函数。
二、init方法特性
1)执行顺序规则
(1)同一个文件多个init方法执行顺序
同一文件内的 init 函数则按照代码编写顺序执行,代码示例如下:
var config string func init() { config = "config1" fmt.Println("init 1:", config) } func init() { fmt.Println("init 2: additional setup") } func main() { fmt.Println("main:", config) }
执行结果如下:
(2)同一个包内执行顺序
同一包内的文件会按照文件名进行字典序排序,并按此顺序执行各文件中的 init 函数。如包内包括a.go和b.go两个文件,优先执行a.go中的init方法,在执行b.go中的init方法。
代码示例如下:
// a.go package main import "fmt" func init() { fmt.Println("a.go init") } // b.go package main import "fmt" func init() { fmt.Println("b.go init") } // main.go package main import "fmt" func init() { fmt.Println("main init") } func main() { fmt.Println("main") }
运行结果如下:
(3)跨包执行顺序
对于跨包依赖的情况,遵循"深度优先"原则,即最后被依赖的包会最先完成初始化。例如在 main → A → B → C 的依赖链中,初始化顺序为 C → B → A → main。
代码包结构如下:
代码示例如下:
// a.go package A import ( "fmt" "te/src/B" ) func init() { fmt.Println("a.go init") } func PrintA() { fmt.Println("print a") B.PrintB() } // b.go package B import ( "fmt" "te/src/C" ) func init() { fmt.Println("b.go init") } func PrintB() { fmt.Println("print b") C.PrintC() } // c.go package C import "fmt" func init() { fmt.Println("c.go init") } func PrintC() { fmt.Println("print c") } // main.go package main import ( "fmt" "te/src/A" ) func init() { fmt.Println("main init") } func main() { fmt.Println("main") A.PrintA() }
执行结果如下:
2)与变量初始化的关系
包级变量初始化优先于 init
执行。示例代码如下:
// 先执行 var config = initConfig() func initConfig() string { fmt.Println("initConfig") return "initConfig" } // 后执行 func init() { config = "init" fmt.Println("init()", config) } func main() { fmt.Println(config) }
运行结果如下:
三、init应用场景
场景 | 用途说明 |
---|---|
全局变量初始化 | 复杂配置加载,如数据库连接池设置 |
驱动/插件注册 | 数据库驱动注册 |
副作用代码执行 | 日志系统初始化,如设设置日志级别和输出格式 |
确保初始化顺序 | 依赖资源预加载,如配置文件读取优先于服务启动 |
四、init使用注意事项
1)避免滥用:过度使用 init 函数会降低代码可读性,建议采用显式初始化方式。对于复杂逻辑,应封装为普通函数并在 main 中显式调用。
2)线程安全:所有 init 函数都在同一个 goroutine 中执行,因此无需加锁。
3)初始化方法应仅包含不会失败的操作 。
到此这篇关于深入理解Go语言init方法的执行顺序的文章就介绍到这了,更多相关Go语言init执行顺序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!