
こんにちは。よっしーです(^^)
本日は、Go言語の言語仕様について解説しています。
背景
Go言語を学び始めて、公式の「The Go Programming Language Specification(言語仕様書)」を開いてみたものの、「英語で書かれていて読むのが大変…」「専門用語ばかりで何を言っているのかわからない…」と感じたことはありませんか? 実は、多くのGo初心者が同じ壁にぶつかっています。
言語仕様書は、Go言語の「正式な取扱説明書」のような存在です。プログラミング言語がどのように動くのか、どんなルールで書くべきなのかが詳しく書かれていますが、その分、初めて読む人には難しく感じられるのも事実です。
そこでこの記事では、言語仕様書の導入部分を丁寧な日本語訳とともに、初心者の方でも理解しやすい補足説明を加えてお届けします。「強く型付けされている」「ガベージコレクション」「並行プログラミング」といった専門用語も、具体例を交えながらわかりやすく解説していきます。
言語仕様書は難しそうに見えますが、一つひとつの概念を丁寧に読み解いていけば、必ず理解できます。一緒に、Go言語の基礎をしっかり学んでいきましょう!
終端文(Terminating statements)
終端文は、ブロック内の通常の制御フローを中断する。以下の文が終端文である:
return文またはgoto文。- 組み込み関数
panicの呼び出し。 - 文リストが終端文で終わるブロック。
- 以下の条件を満たす
if文:else分岐が存在し、かつ- 両方の分岐が終端文である。
- 以下の条件を満たす
for文:- その
for文を参照するbreak文がなく、かつ - ループ条件が存在せず、かつ
- その
for文が range 節を使用していない。
- その
- 以下の条件を満たす
switch文:- その
switch文を参照するbreak文がなく、 - default ケースがあり、かつ
- default を含む各ケースの文リストが、終端文またはラベル付きの場合もある
fallthrough文で終わる。
- その
- 以下の条件を満たす
select文:- その
select文を参照するbreak文がなく、かつ - default が存在する場合はそれを含む各ケースの文リストが終端文で終わる。
- その
- 終端文にラベルを付けたラベル付き文。
その他のすべての文は終端文ではない。
文リストが空でなく、その最後の空でない文が終端文である場合、その文リストは終端文で終わる。
解説
終端文ってなに?
終端文とは、「この先には進まない」とコンパイラが判断できる文のことです。
なぜこの概念が必要かというと、関数宣言の節で学んだように、戻り値を宣言した関数は必ず return で終わらなければならないからです。コンパイラは終端文の定義を使って、「すべてのパスが正しく終了するか」をチェックしています。
func abs(x int) int {
if x >= 0 {
return x
} else {
return -x
}
// ここに到達しないことをコンパイラは理解している
// → if 文が終端文なので OK
}
基本的な終端文
最もシンプルな終端文は return、goto、panic です。
func f() int {
return 42 // 終端文 ✅
}
func g() int {
panic("error") // 終端文 ✅(この先には進まない)
}
if 文が終端文になる条件
if 文が終端文になるには、else があり、かつ両方の分岐が終端文でなければなりません。
// ✅ 終端文:else があり、両方が return で終わる
func sign(x int) string {
if x > 0 {
return "positive"
} else {
return "non-positive"
}
}
// ❌ 終端文ではない:else がない
func bad(x int) string {
if x > 0 {
return "positive"
}
// else がないので、ここに到達する可能性がある
// → この後に return が必要
}
else がない if は、条件が false のとき次の行に進むので、制御フローを完全には止められません。
for 文が終端文になる条件
条件なしの for は無限ループなので、終端文になります。ただし break があると脱出できてしまうのでダメです。
// ✅ 終端文:条件なし、break なし、range なし
func forever() {
for {
doSomething()
}
// この行には到達しない
}
// ❌ 終端文ではない:break がある
func notTerminating() int {
for {
if condition {
break // ループを抜けられる → 終端文ではない
}
}
return 0 // ← これが必要
}
// ❌ 終端文ではない:条件がある
func loop() {
for x > 0 { // 条件が false になるとループを抜ける
x--
}
}
switch 文が終端文になる条件
switch が終端文になるには3つの条件をすべて満たす必要があります。
// ✅ 終端文:default あり、全ケースが return で終わる、break なし
func describe(x int) string {
switch {
case x > 0:
return "positive"
case x < 0:
return "negative"
default:
return "zero"
}
}
// ❌ 終端文ではない:default がない
func incomplete(x int) string {
switch {
case x > 0:
return "positive"
case x < 0:
return "negative"
}
// x == 0 のケースがない → default が必要
return "zero" // ← これが必要
}
実用的な理解:コンパイラの視点
終端文のルールは、コンパイラが「この関数は必ず値を返す」と確信できるかどうかの判定基準です。
func example(x int) int {
if x > 0 {
return 1
}
// コンパイラ:「x <= 0 のときどうするの?」
// → コンパイルエラー:missing return
}
よくある解決パターンは3つです。
// パターン1:else を追加する
func f(x int) int {
if x > 0 {
return 1
} else {
return -1
}
}
// パターン2:関数の最後に return を置く
func f(x int) int {
if x > 0 {
return 1
}
return -1 // すべてのパスをカバー
}
// パターン3:switch の default を使う
func f(x int) int {
switch {
case x > 0:
return 1
default:
return -1
}
}
パターン2は Go で最もよく使われるスタイルです。else を使わず、早期リターンで正常系を先に処理し、最後にデフォルトケースを置くのが Go らしい書き方ですね。
再帰的な定義
終端文の定義は再帰的であることに注目してください。たとえば「ブロックが終端文で終わる」→「そのブロック自体が終端文」→「そのブロックを含む if 文が終端文になりうる」というように、入れ子で判定が進みます。
func f(x int) int {
if x > 0 {
{ // ブロック
fmt.Println(x)
return x // ← このブロックの最後が終端文
} // → このブロック自体が終端文
} else {
return -x
} // → if 文全体が終端文
} // → 関数は正しく終端している
おわりに
本日は、Go言語の言語仕様について解説しました。

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

コメント