# 1. init () 函数概述 🌟
在 Go 语言中, init() 函数是一个特殊的函数,用于执行包级别的初始化操作。它具有独特的执行机制和使用规则,是 Go 语言中重要的特性之一。
# 2. 执行机制 🔄
# 2.1 初始化顺序
Go 程序的初始化顺序如下:
- 包级别变量初始化
init() 函数执行
main() 函数执行
| var X = 100 |
| |
| func init() { |
| X = X * 2 |
| fmt.Println("init:", X) |
| } |
| |
| func main() { |
| fmt.Println("main:", X) |
| } |
| |
| |
| |
| |
# 2.2 多包依赖时的执行顺序
当涉及多个包时,初始化顺序遵循以下规则:
- 按照包的依赖关系,从最底层依赖包开始初始化
- 同一个包中的多个
init() 函数按照它们在文件中的顺序执行
| |
| package a |
| func init() { fmt.Println("init A") } |
| |
| |
| package b |
| import "a" |
| func init() { fmt.Println("init B") } |
| |
| |
| package main |
| import "b" |
| func init() { fmt.Println("init main") } |
| |
| |
| |
| |
| |
# 3. init () 函数的特性 📋
# 3.1 基本特性
- 无参数无返回值:
| func init() { |
| |
| } |
| |
| func init(x int) { |
| |
| } |
| |
| func init() int { |
| |
| return 0 |
| } |
- 自动执行:无需且不能显式调用
- 每个文件可以有多个 init ()
- 所有 init () 都会执行:即使包未被使用
# 3.2 使用场景
- 初始化复杂数据结构:
| var priorityMap map[string]int |
| |
| func init() { |
| priorityMap = make(map[string]int) |
| priorityMap["high"] = 3 |
| priorityMap["medium"] = 2 |
| priorityMap["low"] = 1 |
| } |
- 注册模式:
| var drivers = make(map[string]Driver) |
| |
| func init() { |
| |
| drivers["mysql"] = &MySQLDriver{} |
| drivers["postgres"] = &PostgresDriver{} |
| } |
- 环境检查:
| func init() { |
| if os.Getenv("API_KEY") == "" { |
| log.Fatal("API_KEY environment variable is required") |
| } |
| } |
# 4. 最佳实践 🌟
# 4.1 推荐做法
- 保持简单:
| func init() { |
| |
| cache.Init() |
| metrics.Register() |
| } |
- 错误处理:
| func init() { |
| if err := loadConfig(); err != nil { |
| log.Fatalf("Failed to load config: %v", err) |
| } |
| } |
- 初始化常量映射:
| var statusText map[int]string |
| |
| func init() { |
| statusText = map[int]string{ |
| 200: "OK", |
| 400: "Bad Request", |
| 500: "Internal Server Error", |
| } |
| } |
# 4.2 避免的做法
- ❌ 避免复杂逻辑:
| |
| func init() { |
| |
| for _, user := range users { |
| if user.IsAdmin { |
| |
| } |
| } |
| } |
- ❌ 避免依赖顺序:
| |
| var db *sql.DB |
| |
| func init() { |
| |
| if config == nil { |
| log.Fatal("config not initialized") |
| } |
| } |
- ❌ 避免副作用:
| |
| func init() { |
| |
| os.Setenv("APP_MODE", "production") |
| } |
# 5. 性能考虑 ⚡️
- 初始化开销:
- init () 函数在程序启动时执行
- 过多的 init () 会影响启动时间
- 内存使用:
- 在 init () 中分配的内存会持续整个程序生命周期
- 需要谨慎处理大数据结构的初始化
| |
| var expensive *BigStruct |
| var once sync.Once |
| |
| func getExpensive() *BigStruct { |
| once.Do(func() { |
| expensive = &BigStruct{} |
| }) |
| return expensive |
| } |
# 6. 调试技巧 🔍
- 跟踪 init 执行:
| GODEBUG=inittrace=1 go run main.go |
- 查看初始化依赖:
记住:init () 函数是强大的工具,但应该谨慎使用。保持简单、清晰的初始化逻辑,避免复杂的依赖关系。