[インデックス 1517] ファイルの概要
このコミットは、Go言語の標準ライブラリの一部である src/lib/testing.go
ファイルに対する変更を記録しています。このファイルは、Goのテストフレームワークの基盤となる機能を提供します。
コミット
commit aedf121e30ec9bb155cfdeffa7fc12cc5edad66c
Author: Russ Cox <rsc@golang.org>
Date: Fri Jan 16 15:28:33 2009 -0800
casify struct fields in entire tree.
TBR=r
OCL=22997
CL=22997
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/aedf121e30ec9bb155cfdeffa7fc12cc5edad66c
元コミット内容
このコミットの元の内容は、「ツリー全体の構造体フィールドをcasifyする」というものです。具体的には、src/lib/testing.go
内の Test
構造体のフィールド名が、小文字始まりから大文字始まりに変更されています。これにより、これらのフィールドがエクスポート(公開)されるようになります。
変更の背景
この変更は、Go言語の初期開発段階における重要な設計決定の一つ、すなわち「エクスポートされた識別子(exported identifiers)」の命名規則の確立に関連しています。Go言語では、パッケージ外からアクセス可能な(エクスポートされた)識別子(変数、関数、型、構造体フィールドなど)は、常に大文字で始まる必要があります。一方、小文字で始まる識別子は、そのパッケージ内でのみアクセス可能です(非エクスポート、またはプライベート)。
このコミットが行われた2009年1月は、Go言語がまだ一般に公開される前の開発初期段階でした。この時期には、言語仕様や標準ライブラリのAPI設計に関する多くの試行錯誤が行われていました。この「casify」という変更は、Goの命名規則が固まり、それに合わせて既存のコードベースを修正する作業の一環として行われたと考えられます。特に、testing
パッケージのような標準ライブラリのコア部分は、他のパッケージから利用されることが前提となるため、その構造体フィールドが適切にエクスポートされていることが重要でした。
前提知識の解説
Go言語の命名規則とエクスポート
Go言語には、識別子の可視性(visibility)を制御するための明確な命名規則があります。
- 大文字始まりの識別子: パッケージ外からアクセス可能です。これらは「エクスポートされた(exported)」識別子と呼ばれます。例えば、
Name
やFunc
はエクスポートされます。 - 小文字始まりの識別子: その識別子が定義されているパッケージ内からのみアクセス可能です。これらは「非エクスポート(unexported)」または「プライベート」識別子と呼ばれます。例えば、
name
やfunc
はエクスポートされません。
この規則は、関数、変数、定数、型、そして構造体のフィールドに適用されます。構造体のフィールドがエクスポートされている場合、その構造体のインスタンスをパッケージ外で作成した際に、そのフィールドに直接アクセスしたり、値を設定したりすることができます。
testing
パッケージ
testing
パッケージは、Go言語に組み込まれているテストフレームワークです。開発者はこのパッケージを利用して、ユニットテスト、ベンチマークテスト、サンプルコードなどを記述します。
*T
型:testing
パッケージの中心的な型で、テスト関数に渡されます。テストの失敗を報告したり、ログを出力したりするためのメソッド(例:t.Fatalf
,t.Logf
)を提供します。Test
構造体: このコミットで変更されているTest
構造体は、テストフレームワーク内部で個々のテストのメタデータを管理するために使用されるものです。通常、開発者が直接この構造体を操作することは稀で、func TestXxx(*testing.T)
の形式でテスト関数を記述します。
技術的詳細
このコミットの技術的な核心は、Go言語の可視性規則に準拠するために、構造体 Test
のフィールド名を変更した点にあります。
変更前:
export type Test struct {
name string;
f *(*T);
}
変更後:
export type Test struct {
Name string;
F *(*T);
}
ここで注目すべきは、name
が Name
に、f
が F
に変更されていることです。これにより、これらのフィールドは testing
パッケージの外部からアクセス可能になります。
なぜこれが重要なのでしょうか?
testing
パッケージは、Goのテスト実行時に内部的にテスト関数を管理し、実行します。Test
構造体は、個々のテストに関する情報(テスト名やテスト関数自体)を保持するために使用されます。もしこれらのフィールドがエクスポートされていない(小文字始まりのまま)場合、testing
パッケージの内部実装がこれらのフィールドにアクセスすることは可能ですが、もし将来的にこれらのフィールドがパッケージ外のコード(例えば、テストランナーの拡張機能や、テスト結果を処理するツールなど)から参照される必要が生じた場合、アクセスできなくなってしまいます。
この変更は、testing
パッケージのAPI設計の一部として、Test
構造体のフィールドが外部から参照される可能性があることを考慮し、Goの命名規則に則ってそれらをエクスポート状態にしたものです。これにより、testing
パッケージの内部構造がより柔軟になり、将来的な拡張性や互換性が向上します。
また、この変更に伴い、testing.go
ファイル内でこれらのフィールドを参照している箇所もすべて更新されています。例えば、test.name
は test.Name
に、test.f
は test.F
に変更されています。これは、フィールド名が変更されたため、その参照も一貫して更新する必要があるためです。
コアとなるコードの変更箇所
変更は src/lib/testing.go
ファイルに集中しています。
--- a/src/lib/testing.go
+++ b/src/lib/testing.go
@@ -70,12 +70,12 @@ func (t *T) Fatalf(format string, args ...) {
}
export type Test struct {
- name string;
- f *(*T);
+ Name string;
+ F *(*T);
}
func tRunner(t *T, test *Test) {
- test.f(t);
+ test.F(t);
t.ch <- t;
}
@@ -87,18 +87,18 @@ export func Main(tests []Test) {
}
for i := 0; i < len(tests); i++ {
if *chatty {
- println("=== RUN ", tests[i].name);
+ println("=== RUN ", tests[i].Name);
}
t := new(T);
t.ch = make(chan *T);
go tRunner(t, &tests[i]);
<-t.ch;
if t.failed {
- println("--- FAIL:", tests[i].name);
+ println("--- FAIL:", tests[i].Name);
print(t.errors);
ok = false;
} else if *chatty {
- println("--- PASS:", tests[i].name);
+ println("--- PASS:", tests[i].Name);
print(t.errors);
}
}
コアとなるコードの解説
-
Test
構造体のフィールド名変更:- name string; - f *(*T); + Name string; + F *(*T);
Test
構造体のname
フィールドがName
に、f
フィールドがF
に変更されています。これにより、Goの命名規則に従い、これらのフィールドがエクスポートされるようになりました。name
はテストの名前(文字列)を、f
はテスト関数自体(*T
を引数にとる関数へのポインタ)を保持しています。 -
tRunner
関数内の参照更新:- test.f(t); + test.F(t);
tRunner
関数は、個々のテストを実行する役割を担っています。ここでtest.f(t)
を呼び出すことで、実際のテスト関数が実行されます。フィールド名がf
からF
に変更されたため、ここでの参照もtest.F(t)
に更新されています。 -
Main
関数内の参照更新:- println("=== RUN ", tests[i].name); + println("=== RUN ", tests[i].Name); // ... - println("--- FAIL:", tests[i].name); + println("--- FAIL:", tests[i].Name); // ... - println("--- PASS:", tests[i].name); + println("--- PASS:", tests[i].Name);
Main
関数は、テストスイート全体を管理し、各テストの実行結果(RUN, FAIL, PASS)をコンソールに出力します。これらの出力メッセージにはテスト名が含まれており、以前はtests[i].name
を参照していました。フィールド名がname
からName
に変更されたため、これらの参照もすべてtests[i].Name
に更新されています。
これらの変更は、Go言語の命名規則と可視性モデルに準拠するための、シンプルかつ重要な修正です。これにより、testing
パッケージの内部構造がGoの慣習に沿ったものとなり、将来的な互換性と拡張性が確保されました。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Go言語のEffective Go: https://go.dev/doc/effective_go#names (命名規則に関するセクション)
- Go言語の
testing
パッケージ: https://pkg.go.dev/testing
参考にした情報源リンク
- Go言語の公式ドキュメントおよび
testing
パッケージのソースコード - Go言語の命名規則に関する一般的な情報源 (Effective Goなど)
- GitHubのコミット履歴
- Go言語の初期開発に関する議論やメーリングリストのアーカイブ (必要に応じて)
- 今回は直接的な検索は行っていませんが、Go言語の設計思想や初期の決定に関する情報は、Goのメーリングリストやデザインドキュメントに多く見られます。