初期化

表面的にはCやC++での初期化とあまり変わらないように見えますが、Goでの初期化はより強力です。複雑な構造を初期化中に構築することができ、異なるパッケージ間でも初期化されたオブジェクト間の順序問題が正しく処理されます。

定数

Goの定数は正にその通り、定数です。それらは、関数内でローカルとして定義されても、コンパイル時に作成され、数値、文字(ルーン)、文字列、ブール値のみが可能です。コンパイル時制限のため、それらを定義する式は、コンパイラによって評価可能な定数式でなければなりません。たとえば、1<<3は定数式ですが、math.Sin(math.Pi/4)は実行時にmath.Sinへの関数呼び出しが発生する必要があるため、そうではありません。

Goでは、列挙定数はiota列挙子を使用して作成されます。iotaは式の一部となることができ、式は暗黙的に繰り返されるため、複雑な値のセットを簡単に構築できます。

type ByteSize float64

const (
    _           = iota // ブランク識別子への代入により最初の値を無視
    KB ByteSize = 1 << (10 * iota)
    MB
    GB
    TB
    PB
    EB
    ZB
    YB
)

ユーザー定義型にStringなどのメソッドを添付する能力により、任意の値が印刷時に自動的に自分をフォーマットできます。構造体に最もよく適用されるのを見るでしょうが、この技術はByteSizeのような浮動小数点型などのスカラー型にも有用です。

func (b ByteSize) String() string {
    switch {
    case b >= YB:
        return fmt.Sprintf("%.2fYB", b/YB)
    case b >= ZB:
        return fmt.Sprintf("%.2fZB", b/ZB)
    case b >= EB:
        return fmt.Sprintf("%.2fEB", b/EB)
    case b >= PB:
        return fmt.Sprintf("%.2fPB", b/PB)
    case b >= TB:
        return fmt.Sprintf("%.2fTB", b/TB)
    case b >= GB:
        return fmt.Sprintf("%.2fGB", b/GB)
    case b >= MB:
        return fmt.Sprintf("%.2fMB", b/MB)
    case b >= KB:
        return fmt.Sprintf("%.2fKB", b/KB)
    }
    return fmt.Sprintf("%.2fB", b)
}

YB1.00YBとして印刷され、ByteSize(1e13)9.09TBとして印刷されます。

ここでByteSizeStringメソッドを実装するためにSprintfを使用することは、変換のためではなく、%fSprintfを呼び出すため、安全です(無限再帰を回避)。これは文字列フォーマットではありません:Sprintfは文字列が欲しいときのみStringメソッドを呼び出し、%fは浮動小数点値を要求します。

変数

変数は定数のように初期化できますが、初期化子は実行時に計算される一般的な式にすることができます。

var (
    home   = os.Getenv("HOME")
    user   = os.Getenv("USER")
    gopath = os.Getenv("GOPATH")
)

init関数

最後に、各ソースファイルは、必要な状態を設定するために独自の無引数init関数を定義できます。(実際、各ファイルは複数のinit関数を持つことができます。)そして最後に、それは最後を意味します:initは、パッケージ内のすべての変数宣言がその初期化子を評価した後に呼び出され、これらはすべてのインポートされたパッケージが初期化された後にのみ評価されます。

宣言として表現できない初期化に加えて、init関数の一般的な用途は、実際の実行が開始される前にプログラム状態の正しさを検証または修復することです。

func init() {
    if user == "" {
        log.Fatal("$USER not set")
    }
    if home == "" {
        home = "/home/" + user
    }
    if gopath == "" {
        gopath = home + "/go"
    }
    // gopath はコマンドラインの --gopath フラグによって上書きされる可能性があります
    flag.StringVar(&gopath, "gopath", gopath, "override default GOPATH")
}