總結#
基礎規則:
- 所有的 init 函數都在一個 Goroutine 中執行(但請參見下面的特殊注意)
- 如果 package a 引用了 package b,那麼 a 的 init 一定在 b 的 init 運行完成後運行
- main package 的 main 函數一定在其他 init 函數均運行完成後再運行(即運行順序為 package 的 init -> main 的 init -> main 的 main)
- 同一 package 中的多個文件中的 init 執行順序未定義,同一文件中的 init 自上而下運行
- 如果 package a 同時引用了 package b 和 c,那麼 b 與 c 的 init 順序在 Go1.21 及之後定義
在 Go1.20 及之前:
- 如果 package a 引用了 package b,那麼 b 的 init 一定在 a 之前運行
- 但是,如果 package a 同時引用了 package b 和 c,只要 b c 之間沒有引用關係,b c 的執行順序是不定的
在 Go1.21 及之後:
- 對於無引用關係的包(即 Go1.20 及之前的中的第 2 點),按照其包名字母序決定引用順序(例如 a 一定在 b 之前執行,github.com/xxx/xxx 一定在 gitlab.com/xxx/xxx 之前執行)
特殊注意:
- 如果 init 存在阻塞,那麼用於運行 init 的 goroutine 可能創建新的 goroutine,這會導致某些 init 代碼並發運行
- 存在阻塞的情況下,不會保證無引用關係的 package 的 init 完成先後順序(參考示例 c)
- 存在阻塞的情況下,如果 package a 依賴了 package b,那麼 a 的 init 一定在 b 的 init 運行完成後開始運行(參考示例 d)