[インデックス 1511] ファイルの概要
このコミットは、Go言語の仕様書である doc/go_spec.txt
に加えられた重要な変更を記録しています。主な目的は、Go言語における識別子のエクスポート(公開)メカニズムを根本的に変更し、明示的な export
キーワードや宣言を廃止し、代わりに識別子の先頭文字の大小文字によってエクスポートを制御する新しいルールを導入することです。これにより、言語の簡潔性と一貫性が向上しました。
コミット
commit 83c17606d76f30eafce660d6e64187e628ccb0d0
Author: Robert Griesemer <gri@golang.org>
Date: Fri Jan 16 14:12:50 2009 -0800
- language for export via capitalized identifiers
- removed explicit "export" declarations and keyword
- fixed a few glitches and adjusted examples
(The details of what "export" mean should be clarified
in the spec, this is just so we have a working doc for
now.)
R=r
DELTA=131 (7 added, 63 deleted, 61 changed)
OCL=22753
CL=22970
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/83c17606d76f30eafce660d6e64187e628ccb0d0
元コミット内容
このコミットの元のメッセージは以下の通りです。
- 識別子を大文字にすることでエクスポートする言語仕様の導入
- 明示的な "export" 宣言とキーワードの削除
- いくつかの不具合を修正し、例を調整
("export" の意味の詳細は仕様で明確にする必要があるが、今のところは動作するドキュメントとしてこれを使用する。)
変更の背景
Go言語の初期段階において、識別子の公開(エクスポート)メカニズムは、他の多くのプログラミング言語と同様に、export
のような明示的なキーワードや宣言を用いていました。しかし、Go言語の設計哲学は「シンプルさ」と「簡潔さ」を重視しており、冗長なキーワードや複雑なルールを排除することを目指していました。
このコミットの背景には、以下の課題と目標がありました。
- キーワードの削減:
export
のようなキーワードは、言語の構文を複雑にし、学習コストを増加させる可能性があります。これを排除することで、言語の「表面積」を減らし、よりミニマルな設計を実現します。 - 視覚的な明確さ: 識別子の公開状態を、その名前自体から直感的に判断できるようにすること。これにより、コードを読む際に、その識別子がパッケージ外部からアクセス可能かどうかを一目で理解できるようになります。
- 仕様の簡素化: エクスポートに関する仕様記述を簡素化し、曖昧さを排除すること。特に、構造体やメソッドの部分的なエクスポート、複数ファイルにまたがるパッケージの扱いなど、以前の仕様で「未解決」とされていた項目を、新しいルールで自然に解決することを目指しました。
- 一貫性の向上: 言語全体で一貫したエクスポートルールを適用し、開発者が混乱することなくコードを記述できるようにすること。
これらの背景から、Go言語の設計者たちは、識別子の先頭文字の大小文字によってエクスポートを制御するという、Go言語の特徴的なルールを導入することを決定しました。この変更は、Go言語の設計思想を色濃く反映したものであり、その後のGo言語の普及において重要な役割を果たしました。
前提知識の解説
このコミットの変更内容を理解するためには、以下のGo言語に関する基本的な概念と、一般的なプログラミング言語における「公開(エクスポート)」の概念を理解しておく必要があります。
1. パッケージ (Packages)
Go言語のコードは「パッケージ」という単位で整理されます。パッケージは、関連する機能や型、関数などをまとめたもので、コードのモジュール化と再利用を促進します。他のプログラミング言語における「モジュール」や「名前空間」に近い概念です。
- インポート (Import): 他のパッケージの機能を利用するには、
import
宣言を使ってそのパッケージをインポートする必要があります。 - 可視性 (Visibility): パッケージ内の識別子(変数、関数、型など)には、そのパッケージ内でのみアクセス可能な「内部 (internal)」なものと、他のパッケージからもアクセス可能な「公開 (exported)」なものがあります。
2. 識別子 (Identifiers)
識別子とは、プログラム内で変数、関数、型、定数、メソッド、構造体フィールドなどに名前を付けるために使用される文字列です。
3. エクスポート (Export) / 公開
プログラミング言語において、あるモジュール(Go言語ではパッケージ)内で定義された要素(関数、変数、型など)を、そのモジュールの外部から利用できるようにすることを「エクスポート」または「公開」と呼びます。これは、モジュールのインターフェースを定義し、カプセル化を促進するために不可欠なメカニズムです。
多くの言語では、public
, private
, protected
などのアクセス修飾子キーワードを用いてエクスポートを制御します。例えば、JavaやC#では public
キーワードを付与することで、その要素が公開されることを明示します。
4. Unicode 文字の分類
Go言語の新しいエクスポートルールは、識別子の先頭文字が「大文字」であるかどうかに依存します。ここでいう「大文字」は、ASCII文字だけでなく、Unicodeの「大文字」カテゴリに属する文字も含まれます。Unicodeには、様々な言語の文字が含まれており、それぞれに大文字・小文字の区別があります。
unicode_char
: 任意のUnicodeコードポイント。unicode_letter
: Unicodeで「文字」として分類されるコードポイント。capital_letter
: Unicodeで「文字、大文字」として分類されるコードポイント。
このコミットでは、Go言語の仕様書内でこれらのUnicode文字分類の定義が導入され、エクスポートルールに適用されるようになりました。
技術的詳細
このコミットによって導入されたGo言語のエクスポートメカニズムは、その後のGo言語の設計において非常に重要な要素となりました。その技術的詳細は以下の通りです。
1. 明示的な export
キーワードの廃止
以前のGo言語の仕様では、識別子をエクスポートするために export
キーワードを使用する構文が存在しました。例えば、export const pi float = 3.14159265
のように記述していました。このコミットにより、この export
キーワードは完全に廃止され、予約語のリストからも削除されました。
これにより、宣言の構文も簡素化され、Declaration = [ "export" | "package" ] ( ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl )
から Declaration = ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl
へと変更されました。
2. 識別子の先頭文字の大小文字によるエクスポート制御
Go言語の新しいエクスポートルールは、非常にシンプルかつ強力です。
- エクスポートされる識別子 (Exported identifiers): 識別子の先頭文字が
capital_letter
(Unicodeの大文字) である場合、その識別子はエクスポートされます。エクスポートされた識別子は、その識別子が宣言されたパッケージの外部(他のパッケージ)からアクセス可能です。 - 内部識別子 (Internal identifiers): 識別子の先頭文字が
capital_letter
ではない場合(つまり、小文字で始まるか、アンダースコア_
で始まる場合)、その識別子は内部識別子と見なされます。内部識別子は、その識別子が宣言されたパッケージ内でのみアクセス可能であり、パッケージの外部からはアクセスできません。
このルールは、変数、関数、型、メソッド、定数、構造体フィールドなど、すべての種類の識別子に適用されます。
例:
func MyFunction() {}
(エクスポートされる関数)var MyVariable int
(エクスポートされる変数)type MyStruct struct {}
(エクスポートされる型)func myFunction() {}
(内部関数)var myVariable int
(内部変数)type myStruct struct {}
(内部型)
3. Unicode 文字分類の導入と適用
この変更に伴い、Go言語の仕様書では、識別子の定義においてUnicode文字分類がより厳密に適用されるようになりました。
letter
の定義がunicode_letter | "_"
に変更され、non_ascii
の概念が廃止されました。capital_letter
という新しい分類が導入され、エクスポートルールに直接関連付けられました。
これにより、Go言語はASCII以外の文字を含む識別子に対しても、一貫したエクスポートルールを適用できるようになりました。
4. パッケージの多ファイル構成と部分エクスポートの解決
以前の仕様で「未解決 (Missing)」とされていた以下の項目が、この新しいエクスポートルールによって「解決済み (Closed)」となりました。
[ ] partial export of structs, methods
(構造体、メソッドの部分的なエクスポート)[ ] packages of multiple files
(複数ファイルにまたがるパッケージ)
新しいルールでは、構造体のフィールドやインターフェースのメソッドも、その識別子の先頭文字の大小文字によって個別にエクスポートされるかどうかが決まります。これにより、構造体やインターフェース全体をエクスポートしつつ、その内部の特定のフィールドやメソッドのみを公開するという「部分エクスポート」の概念が、明示的な宣言なしに実現されます。
また、Go言語では一つのパッケージが複数のソースファイルに分割されていても、それらは論理的に一つのパッケージとして扱われます。新しいエクスポートルールは、この多ファイル構成においてもシームレスに機能し、パッケージ内のどのファイルで宣言された識別子であっても、同じルールに基づいてエクスポートが制御されます。
5. 実用的な影響
この変更は、Go言語のコードベース全体に大きな影響を与えました。
- コードの簡潔性:
export
キーワードが不要になったことで、コードがより簡潔になりました。 - 可読性の向上: 識別子の名前を見るだけで、その公開状態が判断できるため、コードの可読性が向上しました。
- 設計の強制: パッケージのAPI設計において、どの要素を公開し、どの要素を内部に留めるべきかという意識が、命名規則に直接反映されるようになりました。これにより、より意図的でクリーンなAPI設計が促進されます。
- 既存コードの修正: この変更は、既存のGo言語のコードベースに大規模な修正を必要としました。特に、
export
キーワードを使用していた箇所や、エクスポートされるべき識別子が小文字で始まっていた箇所は、新しいルールに合わせて修正する必要がありました。
このコミットは、Go言語がその設計哲学を追求し、よりシンプルで効率的な言語へと進化していく過程における、重要なマイルストーンの一つと言えます。
コアとなるコードの変更箇所
このコミットは、Go言語の仕様書である doc/go_spec.txt
のみを変更しています。以下に、主要な変更箇所を抜粋し、その意味を解説します。
1. Exported declarations
セクションの変更
旧:
Exported declarations
----
Global declarations optionally may be marked for ``export'', thus making the
declared identifier accessible outside the current source file. Another source
file may then import the package (§Packages) and access exported identifiers
via qualified identifiers (§Qualified identifiers). Local declarations can
never be marked for export.
There are two kinds of exports: If a declaration in a package P is marked with
the keyword "export", the declared identifier is accessible in any file
importing P; this is called ``unrestricted export''. If a declaration is
marked with the keyword "package", the declared identifier is only accessible
in files belonging to the same package P; this is called ``package-restricted''
export.
If the identifier represents a type, it must be a complete type (§Types) and
the type structure is exported as well. In particular, if the declaration
defines a "struct" or "interface" type, all structure fields and all structure
and interface methods are exported also.
export const pi float = 3.14159265
export func Parse(source string);
package type Node *struct { val int; next *Node }
TODO: Eventually we need to be able to restrict visibility of fields and methods.
(gri) The default should be no struct fields and methods are automatically exported.
Export should be identifier-based: an identifier is either exported or not, and thus
visible or not in importing package.
新:
Exported identifiers
----
Identifiers that start with a capital_letter (§Identifiers) are ``exported'',
thus making the identifiers accessible outside the current package. A file
belonging to another package may then import the package (§Packages) and access
exported identifiers via qualified identifiers (§Qualified identifiers).
All other identifiers are ``internal''; they are only visible in files
belonging to the same package which declares them.
TODO: This should be made clearer. For instance, function-local identifiers
are never exported, but non-global fields/methods may be exported.
解説:
この変更が最も重要です。旧バージョンでは export
キーワードや package
キーワードを用いた明示的なエクスポート宣言について記述されていましたが、新バージョンでは「capital_letter
で始まる識別子はエクスポートされる」という新しいルールが明確に定義されています。これにより、エクスポートのメカニズムがキーワードベースから命名規則ベースへと完全に移行しました。
2. Declaration
構文の変更
旧:
Declaration =
[ "export" | "package" ]
( ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl ) .
新:
Declaration = ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl .
解説:
宣言の構文から [ "export" | "package" ]
の部分が削除されました。これは、export
キーワードが言語から完全に廃止されたことを文法レベルで反映しています。
3. 識別子の定義と capital_letter
の導入
旧:
letter = "A" ... "Z" | "a" ... "z" | "_" | non_ascii.
新:
letter = unicode_letter | "_" .
追加:
The following terms are used to denote specific Unicode character classes:
unicode_char an arbitrary Unicode code point
unicode_letter a Unicode code point classified as "Letter"
capital_letter a Unicode code point classified as "Letter, uppercase"
(The Unicode Standard, Section 4.5 General Category - Normative.)
解説:
識別子を構成する文字の定義が、より汎用的な unicode_letter
を使うように変更されました。そして、capital_letter
という新しい概念が導入され、これがエクスポートのルールに直接結びつけられました。
4. 予約語からの export
の削除
旧:
chan export goto package switch
新:
chan goto package switch
解説:
予約語のリストから export
が削除されました。これは、export
がもはや特別な意味を持つキーワードではないことを示しています。
5. 例の修正
仕様書内の多くの例が、新しいエクスポートルールに合わせて修正されています。
- 定数の例:
const pi float64 = ...
からconst Pi float64 = ...
へ変更され、Pi
がエクスポートされることを示唆。 - 変数の例:
var u, v, w float
からvar U, V, W float
へ変更。 - プライムシーブの例:
Generate
,Filter
,Sieve
といった関数が、パッケージ内部で利用されるためgenerate
,filter
,sieve
と小文字で始まる名前に変更されています。これにより、これらの関数がエクスポートされない(内部関数である)ことが示されています。 - 構造体フィールドの例:
a *[]int; f *();
からA *[]int; F *();
へ変更され、構造体フィールドも大文字で始まることでエクスポートされることを示唆。 - インターフェースメソッドの例:
lock, unlock ();
からLock, Unlock ();
へ変更され、インターフェースメソッドも大文字で始まることでエクスポートされることを示唆。
これらの例の変更は、新しいエクスポートルールが言語のあらゆる側面に適用されることを具体的に示しています。
コアとなるコードの解説
このコミットにおける「コアとなるコード」は、Go言語の仕様書 doc/go_spec.txt
そのものです。このファイルは、Go言語の文法、セマンティクス、および動作を定義する唯一の公式ドキュメントであり、Goコンパイラやツールチェインの実装はこの仕様書に基づいて行われます。
このコミットの核心は、Go言語の「エクスポート」の概念を、明示的なキーワードによる宣言から、識別子の命名規則(先頭文字の大小文字)へと変更した点にあります。
具体的には、以下のセクションがこの変更の核となります。
-
Exported identifiers
セクションの全面的な書き換え: このセクションは、Go言語における識別子の可視性(エクスポートされるか否か)を定義する最も重要な部分です。旧バージョンではexport
キーワードを用いた複雑なルールが記述されていましたが、このコミットによって、**「capital_letter
で始まる識別子はエクスポートされる」**という、Go言語の最も特徴的なエクスポートルールが明確に定義されました。これにより、Go言語のシンプルさと一貫性が大幅に向上しました。 -
Declaration
構文からのexport
キーワードの削除: Go言語の文法を定義するDeclaration
のセクションから、export
キーワードが取り除かれました。これは、言語レベルでexport
キーワードがもはや存在しないことを意味し、コンパイラがこのキーワードを認識しないように変更されることを示唆しています。 -
識別子の定義における
capital_letter
の導入: 識別子を構成する文字の定義にcapital_letter
という概念が導入され、これがエクスポートルールと直接結びつけられました。これにより、Go言語はUnicodeの文字分類を利用して、より国際的な環境での識別子命名にも対応できるようになりました。
これらの変更は、Go言語の設計思想である「シンプルさ」「明示性」「一貫性」を追求した結果であり、Go言語が他のプログラミング言語と一線を画す特徴の一つを形成しました。開発者は、識別子の名前を見るだけでその公開状態を判断できるようになり、コードの可読性と保守性が向上しました。また、コンパイラの実装も、複雑なキーワード解析を必要とせず、よりシンプルなルールに基づいてエクスポートを処理できるようになりました。
関連リンク
- Go言語公式ウェブサイト: https://go.dev/
- Go言語の仕様書 (現在のバージョン): https://go.dev/ref/spec
- Effective Go - Names: https://go.dev/doc/effective_go#names (Go言語の命名規則とエクスポートルールについて解説されています)
参考にした情報源リンク
- Go言語の識別子のエクスポートルールに関するWeb検索結果 (Google Web Search)
- Go言語の識別子のエクスポートルールは、そのシンプルさと明確さから、多くのブログ記事やチュートリアルで解説されています。特に、
public
/private
キーワードを持たないGo言語の設計思想を説明する文脈で頻繁に言及されます。 - https://go.dev/doc/effective_go#names (Effective Go の「名前」のセクションは、このコミットで導入されたエクスポートルールを理解する上で非常に重要です。)
- https://medium.com/@ardanlabs/exported-and-unexported-identifiers-in-go-1f2e3f4d5c6d (Go言語におけるエクスポートされた識別子とエクスポートされない識別子について解説している記事の一例)
- https://www.digitalocean.com/community/tutorials/understanding-packages-in-go (Go言語のパッケージと可視性について解説している記事の一例)
- Go言語の識別子のエクスポートルールは、そのシンプルさと明確さから、多くのブログ記事やチュートリアルで解説されています。特に、