The Go Programming Language Specificationの翻訳、13回目です。
前回までの訳はGo言語仕様[日本語訳]にまとめてあります。
プログラムの初期化と実行
ゼロ値
値を格納するため宣言や、make()
、new()
の呼び出しによりメモリが割り当てられたとき、明示的に初期化をしなければ、そのメモリはデフォルトの初期化が行われます。このような値の要素には、それぞれその型のゼロ値がセットされます。論理値型のゼロ値はfalse
、整数型は0
、浮動小数点型は0.0
、文字列型は""
です。ポインタ、関数、インタフェース、スライス、チャネル、マップ型のゼロ値はnil
です。この初期化は再帰的に行われるので、たとえば構造体が配列のとき、初期値が指定されなければ、各要素のフィールドはゼロ値となります。
次の2つの宣言は等価です。
var i int; var i int = 0;
続いて、
type T struct { i int; f float; next *T }; t := new(T);
これは、下の値を持ちます。
t.i == 0 t.f == 0.0 t.next == nil
次も同じことが当てはまります。
var t T
プログラムの実行
インポートを伴わないパッケージの初期化は、パッケージレベルのすべての変数への初期値代入、およびソース内で定義されている次の名前とシグネチャを持ったパッケージレベルの関数の呼び出しにより行われます。
func init()
パッケージに複数のinit()
関数が含まれるとき(ひとつのソースファイルに複数記述も可)は、順不同で実行されます。
パッケージ内で、パッケージレベルの変数の初期化、および定数値の決定は、それぞれのデータの依存する順で行われます。たとえばA
のイニシャライザがB
の値に依存するならば、A
の値はB
の後に決まります。この依存関係がループしてしまうときはエラーとなります。
依存関係の分析は、辞書的かつ再帰的に行われます。A
の値がB
に影響を受けている、またはA
のイニシャライザがB
の影響を受けている、またはA
が影響を受けている関数がさらにB
の影響を受けているときに、A
はB
に依存しているとみなされます。
ある2つのアイテムがお互いに依存していなければ、それらはソース内に出現した順で初期化されます。依存関係の分析はパッケージごとに行われるため、A
のイニシャライザが、B
を参照している別のパッケージで定義されている関数を呼び出したときの結果は規定されていません。
初期化コードが、“go”ステートメントを含んでいたとしても、全プログラムの初期化が終了するまで、そのステートメントで指定した関数の実行を開始しません。したがって、すべての初期化コードは単一のゴルーチン内で動作します。
init()
関数はプログラムのどこからも参照することができません。すなわち、明示的に呼び出すことも、変数にこの関数のポインタを代入することもできません。
パッケージがインポートを伴うときは、このパッケージ自身の初期化より前に、インポートされたパッケージが初期化されます。ひとつのパッケージを複数回インポートしても、そのパッケージが初期化されるのは一回だけです。
パッケージのインポートでは構造上、初期化の依存関係が循環しないことが保証されています。
完成されたプログラムは、次の関数を持つmain
パッケージを持たなくてはなりません。
func main() { ... }
これは、複数のパッケージを結合して作られたとしても同様です。このmain.main()
関数は、引数および戻り値を持ちません。
プログラムの実行はmain
パッケージを初期化したあと、main.main()
関数を実行することで開始されます。
main.main()
から抜けたときに、プログラムは終了します。このとき、他(main
以外)のゴルーチンの終了待ちは行いません。
実装上の制約:コンパイラはmain
パッケージが、他のどのパッケージからもインポートされることはないと仮定しています。
Comments