Go | 初始化函式的正確使用
💬 簡介
在 Go 語言中,init()
是一個特殊的函式,會在程式啟動與套件載入時自動執行。
雖然設計初衷是為了初始化設定與預備資料,但若使用不當,反而容易造成依賴混亂與維護困難。
本篇將帶你了解
init()
的生命週期、執行順序與建議用法,讓初始化邏輯更加清晰可控。
圖片來源:Gophers
🔍 什麼是 init()
函式?
- 是 Go 語言保留的特殊函式
- 無參數、無回傳值,命名必為
init
- 每個檔案可以有多個
init()
函式 - 自動執行:在
main()
執行之前就會觸發
🔄 執行順序
套件層級執行順序:
依照 import 的依賴關係,自下而上初始化。單一套件中執行順序:
- 全域變數 →
init()
函式(依照原始碼撰寫順序)1
2
3
4
5
6
7
8
9
10package main
import (
"fmt"
_ "myapp/config"
)
func main() {
fmt.Println("Main 函式執行")
}config/init.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14package config
import "fmt"
var AppName string = initName()
func init() {
fmt.Println("執行 init():載入設定")
}
func initName() string {
fmt.Println("執行變數初始化")
return "MyApp"
}執行結果:
1
2
3執行變數初始化
執行 init():載入設定
Main 函式執行
- 全域變數 →
🎯 init()
的適合用途
使用場景 | 說明 |
---|---|
✅ 一次性設定初始化 | 如設定預設值、載入必要資源 |
✅ 註冊機制 | 如 plugin 註冊、自動掛載路由 |
✅ 隱式啟動邏輯 | 如 flag.Parse() 或註冊第三方資源 |
✅ 驗證前置條件 | 僅限不依賴外部變數的快速檢查 |
🚫 不建議的使用方式
誤用方式 | 問題 |
---|---|
❌ 實作邏輯過多 | 不易追蹤初始化流程,降低可維護性 |
❌ 執行順序依賴其他套件 | 容易因初始化順序錯誤導致錯誤發生 |
❌ 操作不可預期副作用 | 隱性修改狀態,程式行為難以預測 |
❌ 模擬「建構子」邏輯 | init() 不該替代明確的初始化函式 |
📌 建議使用模式
✅ 組合使用明確 API
1
2
3
4
5
6
7
8
9
10
11package config
var Env string
func init() {
Env = "production"
}
func GetEnv() string {
return Env
}✅ 或改為顯式初始化函式
1
2
3
4
5
6
7package config
var Env string
func Init() {
Env = "production"
}1
2
3
4
5
6
7
8
9
10package main
import (
"myapp/config"
)
func main() {
config.Init()
// 明確控制初始化時機
}
⚠️ 搭配單元測試的注意
init()
在每次測試執行時都會重新執行一次- 單元測試中盡量避免依賴
init()
狀態,應設計成可注入或明確初始化的結構
🎯 總結
init()
函式是 Go 語言設計中強大但容易誤用的工具。
正確使用能簡化初始化流程,濫用則可能導致架構混亂。
- ✅ 僅用於必要的初始化任務
- ✅ 控制好執行邏輯的輕量與可預測性
- ✅ 複雜邏輯請轉為顯式函式
- ✅ 減少跨套件依賴與隱藏副作用
最後建議回顧一下 Go | 菜鳥教學 目錄,了解其章節內容。
註:以上參考了
Go