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

[インデックス 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)」識別子と呼ばれます。例えば、NameFunc はエクスポートされます。
  • 小文字始まりの識別子: その識別子が定義されているパッケージ内からのみアクセス可能です。これらは「非エクスポート(unexported)」または「プライベート」識別子と呼ばれます。例えば、namefunc はエクスポートされません。

この規則は、関数、変数、定数、型、そして構造体のフィールドに適用されます。構造体のフィールドがエクスポートされている場合、その構造体のインスタンスをパッケージ外で作成した際に、そのフィールドに直接アクセスしたり、値を設定したりすることができます。

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);
}

ここで注目すべきは、nameName に、fF に変更されていることです。これにより、これらのフィールドは testing パッケージの外部からアクセス可能になります。

なぜこれが重要なのでしょうか? testing パッケージは、Goのテスト実行時に内部的にテスト関数を管理し、実行します。Test 構造体は、個々のテストに関する情報(テスト名やテスト関数自体)を保持するために使用されます。もしこれらのフィールドがエクスポートされていない(小文字始まりのまま)場合、testing パッケージの内部実装がこれらのフィールドにアクセスすることは可能ですが、もし将来的にこれらのフィールドがパッケージ外のコード(例えば、テストランナーの拡張機能や、テスト結果を処理するツールなど)から参照される必要が生じた場合、アクセスできなくなってしまいます。

この変更は、testing パッケージのAPI設計の一部として、Test 構造体のフィールドが外部から参照される可能性があることを考慮し、Goの命名規則に則ってそれらをエクスポート状態にしたものです。これにより、testing パッケージの内部構造がより柔軟になり、将来的な拡張性や互換性が向上します。

また、この変更に伴い、testing.go ファイル内でこれらのフィールドを参照している箇所もすべて更新されています。例えば、test.nametest.Name に、test.ftest.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);
 		}
 	}

コアとなるコードの解説

  1. Test 構造体のフィールド名変更:

    -	name string;
    -	f *(*T);
    +	Name string;
    +	F *(*T);
    

    Test 構造体の name フィールドが Name に、f フィールドが F に変更されています。これにより、Goの命名規則に従い、これらのフィールドがエクスポートされるようになりました。name はテストの名前(文字列)を、f はテスト関数自体(*T を引数にとる関数へのポインタ)を保持しています。

  2. tRunner 関数内の参照更新:

    -	test.f(t);
    +	test.F(t);
    

    tRunner 関数は、個々のテストを実行する役割を担っています。ここで test.f(t) を呼び出すことで、実際のテスト関数が実行されます。フィールド名が f から F に変更されたため、ここでの参照も test.F(t) に更新されています。

  3. 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言語の公式ドキュメントおよびtestingパッケージのソースコード
  • Go言語の命名規則に関する一般的な情報源 (Effective Goなど)
  • GitHubのコミット履歴
  • Go言語の初期開発に関する議論やメーリングリストのアーカイブ (必要に応じて)
    • 今回は直接的な検索は行っていませんが、Go言語の設計思想や初期の決定に関する情報は、Goのメーリングリストやデザインドキュメントに多く見られます。