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

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

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

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

スポンサーリンク

背景

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

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

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

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

エクスポートされた識別子(Exported identifiers)

識別子は、他のパッケージからのアクセスを許可するためにエクスポートすることができます。識別子がエクスポートされるのは、以下の両方の条件を満たす場合です。

  1. 識別子の名前の最初の文字が、Unicodeの大文字(Unicode文字カテゴリ Lu)であること。
  2. その識別子がパッケージブロックで宣言されているか、フィールド名またはメソッド名であること。

上記以外の識別子はすべてエクスポートされません。


解説

たとえ話

エクスポートの仕組みをレストランの厨房とホールに例えてみましょう。

パッケージは「レストランの厨房」です。厨房の中にはたくさんの道具や食材(変数・関数・型など)がありますが、お客さん(他のパッケージ)に見せるのはメニューに載った料理だけです。

Goでは、名前の先頭を大文字にする=メニューに載せる(エクスポート)先頭を小文字にする=厨房の中だけで使う(非エクスポート) というルールになっています。

他の多くの言語では public / private といったキーワードを使いますが、Goは名前の先頭1文字だけで可視性を決めるという、非常にシンプルで独特なアプローチを採用しています。

コード例

// ══════════════════════════════════════
// パッケージ: user(user/user.go)
// ══════════════════════════════════════
package user

import "fmt"

// ── 大文字始まり → エクスポートされる(外部から見える) ──

// User は他のパッケージから使える「型」
type User struct {
	Name  string // 大文字始まり → 外部からアクセスできるフィールド
	Email string // 大文字始まり → 外部からアクセスできるフィールド
	age   int    // 小文字始まり → 外部からアクセスできないフィールド
}

// NewUser は他のパッケージから呼べる「関数」
func NewUser(name, email string, age int) User {
	return User{Name: name, Email: email, age: age}
}

// Greet は他のパッケージから呼べる「メソッド」
func (u User) Greet() string {
	return fmt.Sprintf("こんにちは、%sです!", u.Name)
}

// ── 小文字始まり → エクスポートされない(外部から見えない) ──

// validate はこのパッケージ内でしか使えない関数
func validate(email string) bool {
	return len(email) > 0
}

// formatAge はこのパッケージ内でしか使えないメソッド
func (u User) formatAge() string {
	return fmt.Sprintf("%d歳", u.age)
}
// ══════════════════════════════════════
// パッケージ: main(main.go)
// ══════════════════════════════════════
package main

import (
	"fmt"
	"example/user"
)

func main() {
	// ✅ エクスポートされた関数を呼び出す
	u := user.NewUser("太郎", "taro@example.com", 25)

	// ✅ エクスポートされたフィールドにアクセス
	fmt.Println(u.Name)  // → 太郎
	fmt.Println(u.Email) // → taro@example.com

	// ✅ エクスポートされたメソッドを呼び出す
	fmt.Println(u.Greet()) // → こんにちは、太郎です!

	// ❌ エクスポートされていないフィールドにはアクセスできない
	// fmt.Println(u.age) // コンパイルエラー: u.age undefined

	// ❌ エクスポートされていない関数は呼べない
	// user.validate("test") // コンパイルエラー: cannot refer to unexported name

	// ❌ エクスポートされていないメソッドも呼べない
	// u.formatAge() // コンパイルエラー
}
package main

import "fmt"

// ── Unicodeの大文字であればエクスポートされる ──

// 日常的にはASCIIの大文字(A-Z)を使うが、
// 仕様上はUnicodeの大文字カテゴリ(Lu)であればよい

type Über struct { // Ü は Unicode 大文字なのでエクスポートされる
	Ñame string    // Ñ も Unicode 大文字なのでエクスポートされる
}

// ただし、実務では ASCII の A-Z を使うのが一般的です
// 上記は仕様の説明用であり、推奨されるスタイルではありません

func main() {
	v := Über{Ñame: "test"}
	fmt.Println(v.Ñame)
}

よくある間違い・注意点

1. 「2つの条件の両方」を満たす必要がある

大文字で始まるだけではエクスポートされません。パッケージブロックでの宣言、またはフィールド名・メソッド名である必要があります。関数内部のローカル変数は、大文字で始まっていてもエクスポートされません。

func example() {
	// 大文字始まりだが、関数内のローカル変数なのでエクスポートされない
	Message := "これは外部から見えない"
	_ = Message
}

2. 構造体のフィールドを小文字にすると JSON 変換で困る

type Item struct {
	name  string // 小文字 → encoding/json からもアクセスできない
	Price int    // 大文字 → JSON に含まれる
}

// json.Marshal(Item{name: "本", Price: 500})
// → {"Price":500}  ← name が出力されない!

encoding/json などの外部パッケージはリフレクションを使ってフィールドにアクセスしますが、非エクスポートフィールドにはアクセスできません。JSONに含めたいフィールドは必ず大文字始まりにしましょう。

3. エクスポート=公開APIなので慎重に

一度エクスポートした識別子は、他のパッケージから使われる可能性があります。後から名前を変えると利用者のコードが壊れるため、エクスポートする識別子は慎重に設計しましょう。必要最小限だけをエクスポートするのがGoの設計哲学です。

// ✅ 良い設計:必要なものだけエクスポート
type Client struct {
	Timeout int       // 利用者が設定する必要がある → エクスポート
	baseURL string    // 内部実装の詳細 → 非エクスポート
	retries int       // 内部実装の詳細 → 非エクスポート
}

まとめ

  • Goでは、識別子の先頭文字が大文字ならエクスポート(公開)小文字なら非エクスポート(非公開)
  • エクスポートの条件は2つ:①先頭がUnicode大文字、②パッケージブロックで宣言されているかフィールド名・メソッド名であること。
  • 他の言語の public / private に相当する仕組みだが、Goは命名規則だけで実現しているのが特徴。
  • 必要最小限だけをエクスポートし、内部実装は小文字で隠すのがGoらしい設計。
  • JSONエンコードやリフレクションなど、外部パッケージからのアクセスにも影響するため、フィールドの可視性は意識して設計すること。

「大文字=公開、小文字=非公開」というGoのルールは、コードを一目見ただけでAPIの境界が分かるという大きな利点があります。とてもシンプルですが奥が深い仕組みなので、パッケージ設計の際にはぜひ意識してみてください!

おわりに 

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

よっしー
よっしー

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

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

コメント

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