
こんにちは。よっしーです(^^)
本日は、Go言語の言語仕様について解説しています。
背景
Go言語を学び始めて、公式の「The Go Programming Language Specification(言語仕様書)」を開いてみたものの、「英語で書かれていて読むのが大変…」「専門用語ばかりで何を言っているのかわからない…」と感じたことはありませんか? 実は、多くのGo初心者が同じ壁にぶつかっています。
言語仕様書は、Go言語の「正式な取扱説明書」のような存在です。プログラミング言語がどのように動くのか、どんなルールで書くべきなのかが詳しく書かれていますが、その分、初めて読む人には難しく感じられるのも事実です。
そこでこの記事では、言語仕様書の導入部分を丁寧な日本語訳とともに、初心者の方でも理解しやすい補足説明を加えてお届けします。「強く型付けされている」「ガベージコレクション」「並行プログラミング」といった専門用語も、具体例を交えながらわかりやすく解説していきます。
言語仕様書は難しそうに見えますが、一つひとつの概念を丁寧に読み解いていけば、必ず理解できます。一緒に、Go言語の基礎をしっかり学んでいきましょう!
構造体リテラル(Struct literals)
キーなしの構造体リテラルでは、要素リストはフィールドが宣言された順序で各構造体フィールドに対応する要素を含まなければならない。
キーありの構造体リテラルでは、以下のルールが適用される:
- すべての要素にキーがなければならない。
- 各キーは構造体型で宣言されたフィールド名でなければならない。
- 要素リストは各構造体フィールドに対応する要素を持つ必要はない。省略されたフィールドは、そのフィールドのゼロ値を得る。
- 異なるパッケージに属する構造体のエクスポートされていないフィールドに対して要素を指定するとエラーとなる。
以下の宣言が与えられたとき
type Point3D struct { x, y, z float64 }
type Line struct { p, q Point3D }
次のように書くことができる
origin := Point3D{} // Point3D のゼロ値
line := Line{origin, Point3D{y: -4, z: 12.3}} // line.q.x はゼロ値
解説
キーなしとキーあり、2つの書き方
構造体リテラルには2つのスタイルがあります。それぞれルールが異なるので、分けて見ていきましょう。
type Point3D struct { x, y, z float64 }
// キーなし:すべてのフィールドを宣言順に書く
p1 := Point3D{1, 2, 3} // x=1, y=2, z=3
// キーあり:フィールド名を指定して書く
p2 := Point3D{x: 1, y: 2, z: 3}
キーなしの制約:「全部書く・順番通り」
キーなしの場合、フィールドの数と順番がぴったり一致していないとコンパイルエラーになります。
type Point3D struct { x, y, z float64 }
p := Point3D{1, 2} // エラー! z が足りない
p := Point3D{1, 2, 3, 4} // エラー! 多すぎる
フィールドが少ないうちはいいですが、フィールドが増えてくると「3番目って何だっけ?」と混乱しがちです。
キーありの自由度:「好きなものだけ・順不同」
キーありの場合は、ずっと柔軟です。
// 一部のフィールドだけ指定できる(残りはゼロ値)
p := Point3D{y: -4, z: 12.3} // x は 0.0 になる
// 順番も自由
p := Point3D{z: 3, x: 1, y: 2} // OK!
ただし「キーありとキーなしを混ぜる」ことはできません。
p := Point3D{1, y: 2, 3} // エラー! 混在はダメ
キーありが推奨される理由
実際の開発では、キーありの書き方が圧倒的におすすめです。理由は3つあります。
- 読みやすい:どのフィールドに何を入れているか一目でわかる
- 安全:フィールドの順番が変わっても壊れない
- 省略できる:不要なフィールドを書かなくてよい
// キーなし:何が何だかわかりにくい
user := User{"Alice", 30, true, "tokyo", "alice@example.com"}
// キーあり:意味が明確
user := User{
Name: "Alice",
Age: 30,
Email: "alice@example.com",
// Active や City は省略 → ゼロ値になる
}
他パッケージの非公開フィールドには触れない
Go では小文字で始まるフィールドはエクスポートされません(パッケージ外から見えません)。そのため、他のパッケージの構造体をリテラルで作るとき、非公開フィールドに値を指定するとエラーになります。
// 仮に別パッケージに以下の型があるとする
// type point struct { X, y float64 } // X は公開、y は非公開
p := other.Point{X: 1, y: 2} // エラー! y は非公開フィールド
これは逆に言うと、キーなしの書き方は他パッケージの構造体には基本的に使えないことを意味します。すべてのフィールドを書く必要があるのに、非公開フィールドには触れないからです。これもキーありが推奨される理由のひとつですね。
入れ子の構造体リテラル
原文の Line の例は、構造体の中に構造体が入っている(入れ子の)ケースです。
type Point3D struct { x, y, z float64 }
type Line struct { p, q Point3D }
origin := Point3D{} // {0, 0, 0}
line := Line{origin, Point3D{y: -4, z: 12.3}} // キーなしで p と q を指定
Line のリテラルはキーなしなので、1番目の要素が p、2番目が q に対応します。Point3D{y: -4, z: 12.3} はキーありなので、x は省略されてゼロ値(0.0)になります。
キーありで書くとこうなります。
line := Line{
p: origin,
q: Point3D{y: -4, z: 12.3},
}
こちらのほうが、どのフィールドに何を入れているかが明確ですね。
おわりに
本日は、Go言語の言語仕様について解説しました。

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)

コメント