Go言語入門:言語仕様 -Vol.40-

スポンサーリンク
Go言語入門:言語仕様 -Vol.40- 用語解説
Go言語入門:言語仕様 -Vol.40-
この記事は約5分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

本日は、Go言語の言語仕様について解説しています。

スポンサーリンク

背景

Go言語を学び始めて、公式の「The Go Programming Language Specification(言語仕様書)」を開いてみたものの、「英語で書かれていて読むのが大変…」「専門用語ばかりで何を言っているのかわからない…」と感じたことはありませんか? 実は、多くのGo初心者が同じ壁にぶつかっています。

言語仕様書は、Go言語の「正式な取扱説明書」のような存在です。プログラミング言語がどのように動くのか、どんなルールで書くべきなのかが詳しく書かれていますが、その分、初めて読む人には難しく感じられるのも事実です。

そこでこの記事では、言語仕様書の導入部分を丁寧な日本語訳とともに、初心者の方でも理解しやすい補足説明を加えてお届けします。「強く型付けされている」「ガベージコレクション」「並行プログラミング」といった専門用語も、具体例を交えながらわかりやすく解説していきます。

言語仕様書は難しそうに見えますが、一つひとつの概念を丁寧に読み解いていけば、必ず理解できます。一緒に、Go言語の基礎をしっかり学んでいきましょう!

ブロック(Blocks)

ブロックとは、対応する波括弧(ブレース)の中に記述された、宣言や文の並び(空であってもよい)のことです。

Block         = "{" StatementList "}" .
StatementList = { Statement ";" } .

ソースコード上に明示的に記述されるブロックに加えて、暗黙的なブロック(implicit blocks)も存在します。

  1. ユニバースブロックは、すべてのGoソーステキストを包含します。
  2. 各パッケージにはパッケージブロックがあり、そのパッケージに属するすべてのGoソーステキストを含みます。
  3. 各ファイルにはファイルブロックがあり、そのファイル内のすべてのGoソーステキストを含みます。
  4. ifforswitch の各文は、それぞれ独自の暗黙的ブロック内にあるとみなされます。
  5. switch または select 文の各節(clause)は、暗黙的なブロックとして機能します。

ブロックは入れ子(ネスト)になり、スコープに影響を与えます。


解説

たとえ話

ブロックを**「入れ子になった箱」**に例えると分かりやすいです。

一番外側に「宇宙(ユニバース)」という巨大な箱があり、その中に「パッケージ」という中くらいの箱、さらにその中に「ファイル」という小さな箱、そしてファイルの中に iffor で作られるもっと小さな箱がある、というイメージです。

ある箱の中で名前を付けたもの(変数など)は、その箱の中では見えますが、外の箱からは見えません。逆に、外の箱で名前を付けたものは、内側の箱からも見ることができます。これが**スコープ(変数の有効範囲)**の仕組みです。

コード例

package main

import "fmt"

// ここは「ファイルブロック」の中
var global = "ファイル全体から見える変数"

func main() {
	// ここは main 関数の「明示的ブロック」の中
	message := "main関数の中だけで見える"
	fmt.Println(global)  // ✅ 外側のブロックの変数は見える
	fmt.Println(message) // ✅ 同じブロック内なのでOK

	if true {
		// ここは if 文の「暗黙的ブロック」の中
		secret := "ifの中だけの秘密"
		fmt.Println(message) // ✅ 外側(main)の変数は見える
		fmt.Println(secret)  // ✅ 同じブロック内なのでOK
	}

	// fmt.Println(secret) // ❌ コンパイルエラー!ifブロックの外からは見えない
}
package main

import "fmt"

func main() {
	// for 文にも暗黙的ブロックがある
	for i := 0; i < 3; i++ {
		// 変数 i はこの for ブロックの中でだけ有効
		fmt.Println(i) // ✅ OK
	}
	// fmt.Println(i) // ❌ コンパイルエラー!i は for ブロックの外では見えない

	// switch の各 case も暗黙的ブロック
	switch x := 10; {
	case x > 5:
		msg := "大きい"
		fmt.Println(msg) // ✅ OK
	case x <= 5:
		// fmt.Println(msg) // ❌ 別の case ブロックの変数は見えない
		fmt.Println("小さい")
	}
}

よくある間違い・注意点

if ブロック内で宣言した変数を外で使おうとするのは、初心者が最もよくやるミスです。

// ❌ ありがちなミス
if err := doSomething(); err != nil {
	fmt.Println(err)
}
fmt.Println(err) // コンパイルエラー!err は if の暗黙ブロック内でしか有効でない
// ✅ 外でも使いたいなら、先に宣言しておく
var err error
err = doSomething()
if err != nil {
	fmt.Println(err)
}
fmt.Println(err) // OK:外側のブロックで宣言されているので見える

また、外側と同じ名前の変数を内側のブロックで宣言すると、外側の変数が「隠されて(シャドウイング)」しまう点にも注意が必要です。

x := "外側"
if true {
	x := "内側" // 新しい x が作られ、外側の x が隠される
	fmt.Println(x) // → "内側"
}
fmt.Println(x) // → "外側"(外側の x はそのまま)

まとめ

  • ブロックとは {} で囲まれた宣言・文のまとまりのこと。
  • ifforswitch などには目に見えない暗黙的ブロックがある。
  • Goのブロックは入れ子構造になっており、内側から外側は見えるが、外側から内側は見えない。これがスコープのルール。
  • ブロックの境界を意識することで、変数の有効範囲に関するコンパイルエラーやシャドウイングの罠を避けられます。

公式ドキュメントの「ブロック」は短い説明ですが、Goのスコープを理解するうえでとても大切な概念です。ここをしっかり押さえておくと、今後のコードがぐっと書きやすくなりますよ!

おわりに 

本日は、Go言語の言語仕様について解説しました。

よっしー
よっしー

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

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました