Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12315] ファイルの概要

このコミットは、Go言語の仕様書(doc/go_spec.html)における識別子のエクスポートルールと一意性に関する定義を明確化し、修正することを目的としています。特に、エクスポートされた識別子と修飾識別子(qualified identifiers)の動作に関する既存の誤解や不正確さを解消し、識別子の一意性に関する明確な定義を導入しています。

コミット

  • コミットハッシュ: 103c9db74737afc67c394e3c68c746ba176f2b49
  • Author: Robert Griesemer gri@golang.org
  • Date: Thu Mar 1 13:57:49 2012 -0800

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/103c9db74737afc67c394e3c68c746ba176f2b49

元コミット内容

spec: clarifications around exports, uniqueness of identifiers

- Define what it means for two identifiers to be unique.

- The current spec is incorrect about exported
identifiers: for instance, it excluded fields
of non-exported types of exported variables
from being exported. It is easier to leave
the detailed specification away and let the
rest of the spec govern access of exported
identifiers.

- The current spec is incorrect about qualified
identifiers: It simply required that an identifier
be exported to be valid in a qualified identifier.
However, qualified identifiers can only access
exported identifiers declared in the package
block of the imported package.

Fixes #1551.

R=r, rsc, iant, ken
CC=golang-dev
https://golang.org/cl/5711043

変更の背景

このコミットが行われた背景には、Go言語の仕様書における以下の2つの主要な問題がありました。

  1. エクスポートされた識別子の定義の不正確さ: 以前の仕様では、エクスポートされた変数に属する非エクスポート型(unexported types)のフィールドがエクスポートされない、といった誤った記述がありました。これは、Goのモジュール性や可視性(visibility)の原則と矛盾する可能性があり、開発者がエクスポートされた識別子のアクセス範囲を正確に理解する上で混乱を招いていました。コミットメッセージにあるように、「詳細な仕様を省き、残りの仕様でエクスポートされた識別子へのアクセスを管理させる方が簡単」という方針転換がありました。これは、仕様をより簡潔にし、他の関連するルールとの整合性を高めることを意図しています。

  2. 修飾識別子(Qualified Identifiers)の定義の不正確さ: 以前の仕様では、修飾識別子(例: fmt.Println)が有効であるためには、単にその識別子がエクスポートされていることだけを要求していました。しかし、Goのパッケージシステムでは、修飾識別子を通じてアクセスできるのは、インポートされたパッケージの「パッケージブロック(package block)」で宣言されたエクスポートされた識別子に限られます。例えば、パッケージ内で定義された関数や変数、型などがこれに該当します。パッケージブロック外で宣言された識別子(例えば、関数内部で宣言されたローカル変数など)は、たとえエクスポートされていても修飾識別子からはアクセスできません。このコミットは、この重要な制約を仕様に明記することで、修飾識別子の正しい使用法を明確にしました。

これらの問題は、Go言語のセマンティクス(意味論)の正確な理解と、コンパイラの実装における一貫性を確保するために修正が必要でした。特に、Fixes #1551 とあるように、GitHubのIssue #1551で報告された問題に対処しています。

前提知識の解説

このコミットを理解するためには、Go言語における以下の概念を理解しておく必要があります。

  • 識別子(Identifier): プログラム内で名前を付けるために使用される文字列です。変数名、関数名、型名、パッケージ名などが識別子に該当します。
  • エクスポートされた識別子(Exported Identifier): Go言語では、識別子の最初の文字が大文字である場合、その識別子はエクスポートされます。エクスポートされた識別子は、その識別子が宣言されたパッケージの外部からアクセス可能です。これにより、他のパッケージからその機能を利用できるようになります。
  • 修飾識別子(Qualified Identifier): 別のパッケージで宣言された識別子にアクセスするために使用される形式です。パッケージ名.識別子 の形式を取ります(例: fmt.Println)。修飾識別子を通じてアクセスできるのは、エクスポートされた識別子のみです。
  • パッケージブロック(Package Block): Goのプログラムはパッケージに分割されます。各パッケージには、そのパッケージレベルで宣言されたすべての識別子が含まれる「パッケージブロック」があります。これは、関数やメソッドの内部ブロックとは異なり、パッケージ全体で共有されるスコープです。
  • ユニバースブロック(Universe Block): Go言語の最も外側のスコープであり、int, string, true, false, nil, make, new, len, cap, append, panic, recover などの組み込み型や関数、定数が暗黙的に宣言されています。これらはどのパッケージからでも特別なインポートなしに利用できます。
  • 識別子の一意性(Uniqueness of Identifiers): プログラム内で識別子が重複しないことを保証するルールです。Go言語では、特定のスコープ内で同じ名前の識別子を複数宣言することはできません。このコミットでは、この「一意性」の定義がより厳密に定義されています。

技術的詳細

このコミットは、Go言語の仕様書(doc/go_spec.html)に以下の重要な変更を加えています。

  1. 識別子の一意性の明確化:

    • 新しいセクション Uniqueness of identifiers が追加されました。
    • 「識別子のセットが与えられたとき、その識別子がセット内の他のすべての識別子と異なる場合、その識別子は 一意 であると呼ばれる」と定義されています。
    • 「2つの識別子が異なるのは、スペルが異なる場合、または異なるパッケージに現れ、かつエクスポートされていない場合である。それ以外の場合は同じである」という、識別子の「異なる」ことの具体的な条件が明記されました。これは、特にパッケージ間の識別子の可視性(エクスポートの有無)が、その一意性に影響を与えることを示しています。
    • この新しい定義は、メソッドセット、構造体フィールド、インターフェースメソッド、セレクタ式など、Go言語の様々な場所での識別子の一意性に関する既存の記述にリンクとして参照されるようになりました。
  2. エクスポートされた識別子の定義の簡素化と修正:

    • 以前の仕様では、エクスポートされる識別子の条件として、「パッケージブロックで宣言されているか、またはそのブロックで宣言された型のフィールドまたはメソッドであること」という複雑な条件がありました。
    • このコミットでは、この条件が「パッケージブロックで宣言されているか、またはフィールド名またはメソッド名であること」と簡素化されました。これにより、エクスポートのルールがより直感的になり、特に「非エクスポート型のフィールドがエクスポートされない」という誤った解釈を防ぐことができます。
  3. 修飾識別子の定義の厳格化:

    • 以前の仕様では、修飾識別子が有効であるためには、単に「エクスポートされていること」だけを要求していました。
    • このコミットでは、「識別子はエクスポートされており、かつそのパッケージの パッケージブロック で宣言されている必要がある」という条件が追加されました。これは、修飾識別子を通じてアクセスできるのは、インポートされたパッケージのトップレベルで宣言されたエクスポートされた識別子のみであることを明確にしています。これにより、Goのモジュール性とスコープのルールがより厳密に適用されます。
  4. インポート宣言の明確化:

    • インポート宣言が、インポートされたパッケージの機能に依存し、そのパッケージの「エクスポートされた識別子」へのアクセスを可能にすることが明確にされました。
    • 特に、import . "pkg" のようなドットインポート(dot import)の場合、インポートされたパッケージの「パッケージブロックで宣言されたエクスポートされた識別子」が、インポート元のファイルのファイルブロックで宣言され、修飾子なしでアクセスできるようになることが明記されました。これも、修飾識別子の変更と整合しています。

これらの変更は、Go言語の仕様の正確性と一貫性を向上させ、開発者が言語のセマンティクスをより正確に理解できるようにすることを目的としています。

コアとなるコードの変更箇所

変更はすべて doc/go_spec.html ファイルに対して行われています。

  • Uniqueness of identifiers セクションの追加:

    • Blank identifier セクションの後に、新しい Uniqueness of identifiers セクションが追加されました。
    • このセクションで、識別子の一意性と「異なる」ことの定義が記述されています。
  • 既存のセクションからの Uniqueness of identifiers へのリンク追加:

    • メソッドセット、構造体フィールド、インターフェースメソッド、セレクタ式に関する記述で、識別子の一意性が必要な箇所に、新しく追加された Uniqueness of identifiers セクションへのリンクが追加されました。
  • Exported identifiers セクションの修正:

    • エクスポートされる識別子の条件リストの2番目の項目が、より簡潔で正確な記述に修正されました。
      • 変更前: <li>the identifier is declared in the <a href="#Blocks">package block</a> or denotes a field or method of a type declared in that block.</li>
      • 変更後: <li>the identifier is declared in the <a href="#Blocks">package block</a> or it is a <a href="#Struct_types">field name</a> or <a href="#MethodName">method name</a>.</li>
  • Qualified identifiers セクションの修正:

    • 修飾識別子がアクセスできる識別子に関する記述が修正されました。
      • 変更前: The identifier must be <a href="#Exported_identifiers">exported</a> by that package, which means that it must begin with a Unicode upper case letter.
      • 変更後: The identifier must be <a href="#Exported_identifiers">exported</a> and declared in the <a href="#Blocks">package block</a> of that package.
    • 例として math.Sin // denotes the Sin function in package math が追加されました。
  • Import declarations セクションの修正:

    • インポート宣言の目的と、ドットインポート(.)の動作に関する記述が修正されました。
    • 特に、ドットインポートの場合に、インポートされたパッケージの「パッケージブロックで宣言されたエクスポートされた識別子」がインポート元のファイルブロックで利用可能になることが明確にされました。

コアとなるコードの解説

このコミットのコアとなるコードの変更は、Go言語の公式仕様書である doc/go_spec.html のテキスト内容の修正です。これは、Go言語のセマンティクスを定義する最も重要なドキュメントの一つであり、その変更は言語の動作に関する公式な解釈を更新することを意味します。

  • Uniqueness of identifiers の導入: これは、Go言語における識別子の「一意性」という基本的な概念に、初めて明確で厳密な定義を与えたものです。特に、「異なるパッケージに現れ、かつエクスポートされていない場合」に識別子が異なると見なされるというルールは、Goのパッケージシステムと可視性のルールを深く反映しています。これにより、コンパイラの実装者や言語の学習者が、識別子の衝突やスコープに関するルールをより正確に理解できるようになります。

  • エクスポートルールの簡素化: 以前の複雑なエクスポートルールは、特定のケース(例: 非エクスポート型のフィールド)で混乱を招く可能性がありました。新しい簡素化されたルールは、Goの「大文字で始まる識別子はエクスポートされる」という基本的な原則をより直接的に反映し、不必要な例外や複雑さを排除しています。これにより、エクスポートされた識別子のアクセス可能性に関する誤解が減り、コードの可読性と予測可能性が向上します。

  • 修飾識別子の厳格化: 修飾識別子が「パッケージブロックで宣言されたエクスポートされた識別子」のみにアクセスできるという明確化は、Goのパッケージシステムにおけるカプセル化と情報隠蔽の原則を強化します。これにより、開発者はパッケージの内部実装に不適切にアクセスすることを防ぎ、より堅牢で保守しやすいコードを書くことができます。また、コンパイラが修飾識別子の有効性をより正確に検証できるようになります。

これらの変更は、Go言語の設計思想である「シンプルさ」と「明確さ」を仕様レベルで追求したものであり、言語の安定性と一貫性を高める上で非常に重要です。

関連リンク

参考にした情報源リンク