深入理解Go語言init方法的執(zhí)行順序
一、什么是init方法?
init 是 Go 語言中的特殊函數(shù),無需手動調(diào)用,由運行時自動執(zhí)行。每個 .go 文件可以包含多個 init 函數(shù)。init方法沒有參數(shù)和返回值。
示例代碼如下:
func init() {
// 初始化邏輯
}init 函數(shù)在 main() 函數(shù)之前執(zhí)行。當包被導(dǎo)入時,系統(tǒng)會自動調(diào)用所有 init 函數(shù),其調(diào)用順序為:先執(zhí)行依賴包(被導(dǎo)入的包)的 init 函數(shù),再執(zhí)行當前包的 init 函數(shù),最后執(zhí)行 main() 函數(shù)。
二、init方法特性
1)執(zhí)行順序規(guī)則
(1)同一個文件多個init方法執(zhí)行順序
同一文件內(nèi)的 init 函數(shù)則按照代碼編寫順序執(zhí)行,代碼示例如下:
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)
}執(zhí)行結(jié)果如下:

(2)同一個包內(nèi)執(zhí)行順序
同一包內(nèi)的文件會按照文件名進行字典序排序,并按此順序執(zhí)行各文件中的 init 函數(shù)。如包內(nèi)包括a.go和b.go兩個文件,優(yōu)先執(zhí)行a.go中的init方法,在執(zhí)行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")
}運行結(jié)果如下:

(3)跨包執(zhí)行順序
對于跨包依賴的情況,遵循"深度優(yōu)先"原則,即最后被依賴的包會最先完成初始化。例如在 main → A → B → C 的依賴鏈中,初始化順序為 C → B → A → main。
代碼包結(jié)構(gòu)如下:

代碼示例如下:
// 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()
}執(zhí)行結(jié)果如下:

2)與變量初始化的關(guān)系
包級變量初始化優(yōu)先于 init 執(zhí)行。示例代碼如下:
// 先執(zhí)行
var config = initConfig()
func initConfig() string {
fmt.Println("initConfig")
return "initConfig"
}
// 后執(zhí)行
func init() {
config = "init"
fmt.Println("init()", config)
}
func main() {
fmt.Println(config)
}運行結(jié)果如下:

三、init應(yīng)用場景
| 場景 | 用途說明 |
|---|---|
| 全局變量初始化 | 復(fù)雜配置加載,如數(shù)據(jù)庫連接池設(shè)置 |
| 驅(qū)動/插件注冊 | 數(shù)據(jù)庫驅(qū)動注冊 |
| 副作用代碼執(zhí)行 | 日志系統(tǒng)初始化,如設(shè)設(shè)置日志級別和輸出格式 |
| 確保初始化順序 | 依賴資源預(yù)加載,如配置文件讀取優(yōu)先于服務(wù)啟動 |
四、init使用注意事項
1)避免濫用:過度使用 init 函數(shù)會降低代碼可讀性,建議采用顯式初始化方式。對于復(fù)雜邏輯,應(yīng)封裝為普通函數(shù)并在 main 中顯式調(diào)用。
2)線程安全:所有 init 函數(shù)都在同一個 goroutine 中執(zhí)行,因此無需加鎖。
3)初始化方法應(yīng)僅包含不會失敗的操作 。
到此這篇關(guān)于深入理解Go語言init方法的執(zhí)行順序的文章就介紹到這了,更多相關(guān)Go語言init執(zhí)行順序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go?for-range?的?value值地址每次都一樣的原因解析
循環(huán)語句是一種常用的控制結(jié)構(gòu),在?Go?語言中,除了?for?關(guān)鍵字以外,還有一個?range?關(guān)鍵字,可以使用?for-range?循環(huán)迭代數(shù)組、切片、字符串、map?和?channel?這些數(shù)據(jù)類型,這篇文章主要介紹了Go?for-range?的?value值地址每次都一樣的原因解析,需要的朋友可以參考下2023-05-05
golang提示dial?tcp?172?.217.163.49:443:?connectex:?A?con
這篇文章主要為大家介紹了golang提示dial?tcp?172?.217.163.49:443:?connectex:?A?connection?attempt?failed解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07
Golang空結(jié)構(gòu)體struct{}用途,你知道嗎
這篇文章主要介紹了Golang空結(jié)構(gòu)體struct{}用途,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
基于gin的golang web開發(fā)之認證利器jwt
這篇文章主要介紹了基于gin的golang web開發(fā)之認證利器jwt,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12
Goland調(diào)節(jié)字體大小的設(shè)置(編輯區(qū),terminal區(qū),頁面字體)
這篇文章主要介紹了Goland調(diào)節(jié)字體大小的設(shè)置(編輯區(qū),terminal區(qū),頁面字體),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12

