😺
Goのinit関数の役割と特別性
現在、Goを使ってwebサービスのbackendを書いている中でinit関数を扱ったので、忘備録として書いておきます。
以下がその時に書いたコードのinit()部分を抜き出した部分です。
var jwtKey *ecdsa.PrivateKey
func init() {
privateKeyPath := os.Getenv("JWT_SECRET") // 環境変数には鍵のpathを設定
keyData, err := ioutil.ReadFile(privateKeyPath)
if err != nil {
panic("failed to read private key file")
}
block, _ := pem.Decode(keyData)
if block == nil || block.Type != "EC PRIVATE KEY" {
panic("failed to decode PEM block containing ECDSA private key")
}
privateKey, err := x509.ParseECPrivateKey(block.Bytes)
if err != nil {
panic("failed to parse ECDSA private key")
}
jwtKey = privateKey
}
上記のinit()はECDSA秘密鍵が書いているファイルのPathを環境変数から読み込み、秘密鍵をグローバル変数のjwtKeyに代入しています。
このコードでは、init()を明示的に実行している場所がありません。
一般的な関数
通常の関数は定義をしたら、下記のように関数名を書かないと実行されません。
package main
import "fmt"
func test() {
for i := 1; i <= 100; i += 1 {
fmt.Println(i)
}
}
func main() {
test()
}
test()をコメントアウトしたら、実行しても何も表示されません。
init()
しかし、下記のように関数名をinitに変えるとmain()にinit()と書かなくても実行されます。
package main
import "fmt"
func init() {
for i := 1; i <= 100; i += 1 {
fmt.Println(i)
}
}
func main() {
}
init()の実行ルール
実行されるルールとしては以下のとおりです。
init()が書かれたpackageが初めて使用されるタイミングであり、package内の他のコードよりも先に実行される。
また、package内で複数のinit()を定義できる。実行される順番としては定義された順に実行される。
Discussion