本篇基于 Go 1.25.1 版本,带你彻底搞懂 init 函数的执行时机、作用、执行顺序,掌握程序初始化的核心机制!
一、init 函数是什么?
init 函数是 Go 语言中的包初始化函数,是 Go 内置的特殊函数。
核心特点:
- • 自动执行,无需手动调用
- • 每个包、每个文件可以写多个 init
- • 无参数、无返回值
- • 执行时机比 main 更早
- • 常用于:初始化配置、加载变量、注册、校验
二、init 函数执行顺序(最重要!)
执行优先级从先到后:
- 1. 初始化被导入的包的变量
- 2. 执行被导入包的 init
- 3. 初始化当前包变量
- 4. 执行当前包的 init
- 5. 最后执行 main 函数
一句话总结:
先依赖 → 再当前 → 最后 main
三、语法格式
func init() {
// 初始化逻辑
}- • 无参数
- • 无返回值
- • 不能被调用
- • 一个文件可写多个
四、核心知识点表格
| 特性 | 说明 |
|---|---|
| 执行时机 | 程序启动时自动执行,早于 main |
| 调用方式 | 自动调用,不能手动调用 |
| 数量 | 一个文件/包可定义多个 |
| 作用 | 初始化配置、注册、变量、校验 |
| 依赖包 | 先执行依赖包的 init,再执行当前包 |
| 执行顺序 | 同一文件中,从上到下执行 |
五、完整可运行 Demo(本地直接跑)
项目结构
init-demo/
├── go.mod
├── main.go
└── config/
└── config.go1. config/config.go
package config
import "fmt"
// 包变量初始化(最先执行)
var AppName = "GoApp"
// init 1
func init() {
fmt.Println("[config] init 1 执行")
}
// init 2(同一个包可以写多个)
func init() {
fmt.Println("[config] init 2 执行")
}
// 加载配置
func Load() {
fmt.Println("[config] 配置加载完成:", AppName)
}2. main.go
package main
import (
"init-demo/config"
"fmt"
)
// 主包变量初始化
var version = "1.0.0"
// init 1
func init() {
fmt.Println("[main] init 1 执行")
}
// init 2
func init() {
fmt.Println("[main] init 2 执行")
}
// 最后执行 main
func main() {
fmt.Println("[main] main 函数开始执行")
config.Load()
fmt.Println("程序启动成功!版本:", version)
}六、运行命令
go mod init init-demo
go run main.go七、运行结果(看执行顺序!)
[config] init 1 执行
[config] init 2 执行
[main] init 1 执行
[main] init 2 执行
[main] main 函数开始执行
[config] 配置加载完成:GoApp
程序启动成功!版本:1.0.0八、执行顺序图解
- 1. 初始化
config包变量 - 2. 执行
config所有 init - 3. 初始化
main包变量 - 4. 执行
main所有 init - 5. 执行
main函数
九、init 函数最常用场景
✅ 初始化配置文件
✅ 注册插件/服务
✅ 初始化数据库连接
✅ 校验环境变量
✅ 初始化全局变量
✅ 注册路由、日志、监控
十、新手避坑指南
- 1. init 不能被调用
- 2. 不要在 init 里写耗时逻辑
- 3. 不要依赖多个 init 的执行顺序
- 4. init 执行失败会直接导致程序崩溃
📌 总结
- 1. init 是包初始化函数,自动执行
- 2. 先执行依赖包 → 再当前包 → 最后 main
- 3. 一个文件可写多个 init
- 4. 用于初始化、配置、注册、校验
- 5. 是 Go 程序启动的秘密第一道关卡
掌握 init,你才算真正理解 Go 程序启动流程 ✨
MiaoAll