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

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

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

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

スポンサーリンク

背景

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

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

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

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

事前宣言された識別子(Predeclared identifiers)

以下の識別子は、ユニバースブロックにおいて暗黙的に宣言されています [Go 1.18] [Go 1.21]。

型(Types):
	any bool byte comparable
	complex64 complex128 error float32 float64
	int int8 int16 int32 int64 rune string
	uint uint8 uint16 uint32 uint64 uintptr

定数(Constants):
	true false iota

ゼロ値(Zero value):
	nil

関数(Functions):
	append cap clear close complex copy delete imag len
	make max min new panic print println real recover

解説

たとえ話

事前宣言された識別子は、「プログラミング言語に最初から入っている標準装備」 です。

新しいスマートフォンを買ったとき、電話アプリやカメラアプリが最初からインストールされていますよね。自分でダウンロードしなくても使えます。Goの事前宣言された識別子もまったく同じで、import も宣言も不要で、どのファイルからでもそのまま使えます。

これらがユニバースブロックに属しているということは、前回までの「ブロックとスコープ」の解説で学んだ通り、プログラム全体のどこからでもアクセスできるということです。

コード例

package main

import "fmt"

func main() {
	// ══════════════════════════════════
	// 事前宣言された「型」の使用例
	// ══════════════════════════════════

	var flag bool = true          // bool: 真偽値
	var age int = 25              // int: 整数
	var price float64 = 1980.5    // float64: 浮動小数点数
	var name string = "Gopher"    // string: 文字列
	var initial byte = 'G'        // byte: uint8 の別名(1バイト)
	var letter rune = 'あ'        // rune: int32 の別名(Unicode文字1つ)

	fmt.Println(flag, age, price, name, initial, letter)
}
package main

import "fmt"

func main() {
	// ══════════════════════════════════
	// 事前宣言された「定数」の使用例
	// ══════════════════════════════════

	fmt.Println(true)  // true: 真
	fmt.Println(false) // false: 偽

	// iota: const ブロック内で連番を自動生成する特殊な定数
	const (
		Red   = iota // 0
		Green        // 1
		Blue         // 2
	)
	fmt.Println(Red, Green, Blue) // → 0 1 2
}
package main

import "fmt"

func main() {
	// ══════════════════════════════════
	// 事前宣言された「ゼロ値」の使用例
	// ══════════════════════════════════

	// nil: ポインタ、スライス、マップ、チャネル、関数、インターフェースのゼロ値
	var p *int = nil
	var s []int = nil
	var m map[string]int = nil

	fmt.Println(p, s, m) // → <nil> [] map[]
}
package main

import "fmt"

func main() {
	// ══════════════════════════════════
	// 事前宣言された「関数」の使用例
	// ══════════════════════════════════

	// make: スライス、マップ、チャネルを初期化する
	nums := make([]int, 0, 10)

	// append: スライスに要素を追加する
	nums = append(nums, 1, 2, 3)

	// len: 長さを返す / cap: 容量を返す
	fmt.Println("長さ:", len(nums), "容量:", cap(nums)) // → 長さ: 3 容量: 10

	// new: 型のゼロ値へのポインタを返す
	ptr := new(int)
	fmt.Println("ポインタの値:", *ptr) // → 0

	// copy: スライスの要素をコピーする
	src := []int{10, 20, 30}
	dst := make([]int, 3)
	copy(dst, src)
	fmt.Println("コピー結果:", dst) // → [10 20 30]

	// delete: マップからキーを削除する
	colors := map[string]string{"r": "赤", "g": "緑"}
	delete(colors, "r")
	fmt.Println("削除後:", colors) // → map[g:緑]

	// max / min: 最大値・最小値を返す(Go 1.21 以降)
	fmt.Println("最大:", max(1, 5, 3))  // → 5
	fmt.Println("最小:", min(1, 5, 3))  // → 1

	// clear: スライスやマップの要素をクリアする(Go 1.21 以降)
	data := []int{1, 2, 3}
	clear(data)
	fmt.Println("クリア後:", data) // → [0 0 0](長さは変わらず、ゼロ値に戻る)
}
package main

import "fmt"

// ══════════════════════════════════
// any と comparable(Go 1.18 以降)
// ══════════════════════════════════

// any: interface{} の別名。あらゆる型を受け取れる
func printAnything(v any) {
	fmt.Println(v)
}

// comparable: == や != で比較できる型の制約(ジェネリクスで使用)
func contains[T comparable](slice []T, target T) bool {
	for _, v := range slice {
		if v == target {
			return true
		}
	}
	return false
}

func main() {
	printAnything(42)
	printAnything("hello")

	fmt.Println(contains([]int{1, 2, 3}, 2))       // → true
	fmt.Println(contains([]string{"a", "b"}, "c"))  // → false
}

よくある間違い・注意点

1. 事前宣言された識別子はシャドウイング(上書き)できてしまう

これは最も危険な落とし穴です。inttrue などは予約語ではなく、単にユニバースブロックで宣言された識別子に過ぎません。そのため、内側のブロックで同名の変数を作ると隠されてしまいます。

// ❌ 絶対にやってはいけない!しかし文法上は合法
func bad() {
	true := 0         // bool の true が隠されてしまう!
	int := "文字列"    // 型の int が隠されてしまう!
	len := 42         // 組み込み関数 len が隠されてしまう!

	// もう本来の true, int, len は使えない…
	_ = true
	_ = int
	_ = len
}

2. print / println は開発用。本番では fmt を使う

事前宣言された printprintln はデバッグ用の簡易関数であり、出力先が標準エラー出力(stderr)です。フォーマット機能もないため、本番コードでは fmt.Printfmt.Println を使いましょう。

3. nil は型ではなく値

// ❌ nil を型のように使うことはできない
// var x nil // コンパイルエラー

// ✅ nil はポインタ・スライス・マップなどのゼロ値として使う
var p *int = nil

4. バージョンによる追加に注意

anycomparable は Go 1.18 で、maxminclear は Go 1.21 で追加されました。古いバージョンの Go を使っている環境では利用できません。go.modgo ディレクティブでバージョンを確認しましょう。

まとめ

  • 事前宣言された識別子は、ユニバースブロックに属するため import なしでどこでも使える。
  • intstringboolany など)、定数truefalseiota)、ゼロ値nil)、組み込み関数lenmakeappend など)の4カテゴリがある。
  • これらは予約語ではないため、同名の変数を作ると隠される(シャドウイング)。絶対に避けるべき。
  • any / comparable(Go 1.18)や max / min / clear(Go 1.21)など、バージョンによって追加された識別子もあるので、使用する Go のバージョンを確認すること。

事前宣言された識別子は、Goプログラムの「基本語彙」のようなものです。これらを正しく理解しておくと、Goの型システムや組み込み関数をスムーズに使いこなせるようになりますよ!

おわりに 

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

よっしー
よっしー

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

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

コメント

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