Go 初始化

Gary Liao
3 min readJun 6, 2023

--

神說有光就有光

本篇介紹兩種 Go 做初始化的方式。

init()

作為初始化的工具,任何 .go 檔案裏面都可以有複數個 init() ,執行順序從上到下;任何package被import的時候都會依照import 的順序被初始化一次,main package 最後初始化。

package main

import (
"fmt"
)

var a, b int

func main() {
fmt.Println(a, b) // 1 2
}

func init() {
a = 1
}

func init() {
b = 2
}

某方大大對於init() 的更多探討與優缺,提到了 init() 做了什麼事情、何時何地被呼叫、順序…等,太過隱晦。

根據我找到的這篇,官方提出了一個補救措施,就可以顯示init()被執行的順序以及時間等資訊:

GODEBUG=inittrace=1 go run main.go

結果長這樣

init internal/bytealg @0.010 ms, 0 ms clock, 0 bytes, 0 allocs
init runtime @0.067 ms, 0.10 ms clock, 0 bytes, 0 allocs
init errors @0.77 ms, 0.007 ms clock, 0 bytes, 0 allocs
init sync @0.84 ms, 0.002 ms clock, 16 bytes, 1 allocs
init io @0.87 ms, 0.006 ms clock, 144 bytes, 9 allocs

... 更多

sync.Once

sync.Once 提供了一種叫做 lazy initialization 的機制,因為有些變數初始化之後又用不見得用得到,徒增初始化時間與浪費空間,因此可以延遲到需要用的時候才進行初始化。使用這個方式被呼叫多次的function,只有第一次會真正被執行,後面都會略過:

package main

import (
"fmt"
"sync"
)

var a, b int
var DoOnce sync.Once

func main() {
PrintAB()
PrintAB()
PrintAB()
}

func MyInit() {
fmt.Println("Executing MyInit()")
a = 1
b = 2
}

func PrintAB() {
DoOnce.Do(MyInit)
fmt.Println(a, b)
}

執行結果

Executing MyInit()
1 2
1 2
1 2

--

--