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の影響を受けているときに、ABに依存しているとみなされます。
ある2つのアイテムがお互いに依存していなければ、それらはソース内に出現した順で初期化されます。依存関係の分析はパッケージごとに行われるため、Aのイニシャライザが、Bを参照している別のパッケージで定義されている関数を呼び出したときの結果は規定されていません。

初期化コードが、“go”ステートメントを含んでいたとしても、全プログラムの初期化が終了するまで、そのステートメントで指定した関数の実行を開始しません。したがって、すべての初期化コードは単一のゴルーチン内で動作します。

init()関数はプログラムのどこからも参照することができません。すなわち、明示的に呼び出すことも、変数にこの関数のポインタを代入することもできません。

パッケージがインポートを伴うときは、このパッケージ自身の初期化より前に、インポートされたパッケージが初期化されます。ひとつのパッケージを複数回インポートしても、そのパッケージが初期化されるのは一回だけです。

パッケージのインポートでは構造上、初期化の依存関係が循環しないことが保証されています。

完成されたプログラムは、次の関数を持つmainパッケージを持たなくてはなりません。

func main() { ... }

これは、複数のパッケージを結合して作られたとしても同様です。このmain.main()関数は、引数および戻り値を持ちません。

プログラムの実行はmainパッケージを初期化したあと、main.main()関数を実行することで開始されます。

main.main()から抜けたときに、プログラムは終了します。このとき、他(main以外)のゴルーチンの終了待ちは行いません。

実装上の制約:コンパイラはmainパッケージが、他のどのパッケージからもインポートされることはないと仮定しています。