Goアドベントカレンダーの穴埋め投稿です。
他の初期化処理に先駆けて、真っ先に何かをやりたいことってないですか?ありますよね?
initの呼び出し順序
Go処理系の実装依存であって、仕様はないのですが、Python同様Goは主要実装が仕様なところがあるのでこれに従って説明します。ググるといろいろ情報が出てきます。
Package initialization and program execution order
- mainパッケージの初期化
- 自身のパッケージの前にimportされているパッケージを初期化
- パッケージは1度にひとつずつ初期化される
- パッケージレベルの変数は宣言順に初期化される
- 最後に自分の中のinitが呼ばれる
- 最後にmain関数を呼ぶ
ここに書いてない情報としては、パッケージ内部の順序というのはファイル名の順序で規定されます。あと、init関数はパッケージ内部に同名関数をいくつも定義できますが、複数ある場合もパッケージ内部の順序(ファイル名順→ファイル内宣言順)で呼ばれます。
最速で呼ぶには
最速のファイル名を定義して、その中からimportして、その中にロジックを書くのが最速ということです。最速なのはゼロドットゴーです。
package main
import _ "github.com/shibukawa/fastest"
これのためにわざわざリポジトリを作るのはあれなので、fastestサブフォルダを作ってgo.modでreplaceでそういうパッケージがあるように見せかけます。
module fastest_test
go 1.13
replace github.com/shibukawa/fastest => ./fastest
これが最速で呼ばれるコードです。
package fastest
import "log"
func init() {
log.Println("最速で呼ばれるinit")
}
これで最速でなにかやりたいときはバッチリです!まあ実装するのがツールやらライブラリならgo.modのreplaceはやらなくても良くて、そのパッケージのサブパッケージで指定すれば良いですね。今回はコードジェネレータで置き場所が事前に決まらない、みたいなユースケースで解法を考えたのでreplace使っています。