[インデックス 1480] ファイルの概要
このコミットは、Go言語の標準ライブラリの一部である tabwriter
パッケージにおける命名規則の変更を扱っています。具体的には、tabwriter
パッケージ内の型や関数の識別子を、外部に公開される(エクスポートされる)ものから、パッケージ内部でのみ使用される(アンエクスポートされる)ものへと変更しています。これは、Go言語における識別子の可視性(visibility)に関する重要な慣習に則った変更です。
コミット
commit e28692f07d6b476ff9c684577cf11877fdb8991d
Author: Robert Griesemer <gri@golang.org>
Date: Thu Jan 15 15:10:46 2009 -0800
- converted tabwriter to new naming scheme
R=r
OCL=22870
CL=22870
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e28692f07d6b476ff9c684577cf11877fdb8991d
元コミット内容
このコミットの目的は、tabwriter
パッケージ内の識別子を新しい命名スキームに変換することです。具体的には、ByteArray
型が byteArray
に、AddLine
関数が addLine
に、Write0
関数が write0
に、Newline
変数が newline
に、WritePadding
関数が writePadding
に、WriteLines
関数が writeLines
に、Format
関数が format
に、UnicodeLen
関数が unicodeLen
に、Append
関数が append
に、Buffer
型が buffer
に、Init
関数が init
に、Clear
関数が clear
に、Write
関数が write
に、String
関数が string
に、Verify
関数が verify
に、Check
関数が check
にそれぞれ変更されています。
変更の背景
Go言語では、識別子(変数、関数、型など)の最初の文字が大文字であるか小文字であるかによって、その可視性(スコープ)が決定されます。
- 大文字で始まる識別子: パッケージ外からアクセス可能(エクスポートされる)。
- 小文字で始まる識別子: パッケージ内でのみアクセス可能(アンエクスポートされる)。
このコミットが行われた2009年1月は、Go言語がまだ初期開発段階にあり、言語仕様や標準ライブラリの設計が固まりつつある時期でした。tabwriter
パッケージは、テキストを整形してタブ区切りの列を揃えるためのユーティリティを提供します。このコミット以前は、パッケージ内部でしか使われないはずの多くの型や関数が、誤って大文字で始まり、外部にエクスポートされている状態でした。
この変更の背景には、Go言語の設計思想である「シンプルさ」と「明示性」があります。パッケージの内部実装の詳細を外部に公開しないことで、APIの安定性を保ち、利用者が混乱するのを防ぎます。また、不必要なエクスポートを避けることで、コンパイル時の依存関係を減らし、コードの保守性を向上させる狙いもあります。
前提知識の解説
Go言語の命名規則と可視性
Go言語の命名規則は非常にシンプルで、識別子の最初の文字がその可視性を決定します。
- エクスポートされた識別子 (Exported Identifiers): 識別子の最初の文字が大文字の場合、その識別子はパッケージの外部からアクセス可能です。これは、他のパッケージからインポートして使用できることを意味します。例えば、
fmt.Println
のPrintln
は大文字で始まるため、fmt
パッケージの外部から呼び出すことができます。 - アンエクスポートされた識別子 (Unexported Identifiers): 識別子の最初の文字が小文字の場合、その識別子は宣言されたパッケージ内でのみアクセス可能です。これは、パッケージの内部実装の詳細であり、外部からは直接利用できないことを意味します。例えば、
sync
パッケージ内の多くの内部ヘルパー関数は小文字で始まります。
この規則は、Go言語のAPI設計において非常に重要です。外部に公開すべきものだけをエクスポートし、内部実装は隠蔽することで、モジュール性とカプセル化を促進します。
tabwriter
パッケージの役割
text/tabwriter
(コミット当時は src/lib/tabwriter
) パッケージは、Go言語の標準ライブラリの一部で、テキストデータを整形し、タブ区切りの列を自動的に揃える機能を提供します。これは、コマンドラインツールやログ出力などで、整形された表形式のデータを表示する際に非常に便利です。tabwriter.Writer
型は io.Writer
インターフェースを実装しており、任意の io.Writer
にデータを書き込むことができます。内部的には、タブ文字 (\t
) や改行文字 (\n
) を解析し、各列の幅を計算して適切なパディング(空白や指定された文字)を挿入することで、列を揃えます。
技術的詳細
このコミットの技術的な変更は、主にGo言語の識別子のリネームに集約されます。具体的には、tabwriter.go
と tabwriter_test.go
の両ファイルにおいて、以下のパターンでリネームが行われています。
-
型名の変更:
ByteArray
->byteArray
Buffer
->buffer
これらの型は、tabwriter
パッケージの内部実装で使用される補助的なデータ構造であり、外部に公開する必要がないため、アンエクスポートされました。
-
メソッド名の変更:
(*ByteArray).Init
->(*byteArray).Init
(ただし、Init
はinit
に変更されていない点に注意。これはInit
がWriter
の初期化に使われるため、外部から呼び出される可能性があるためか、あるいは初期のGoの慣習がまだ固まっていなかったためかもしれない)(*ByteArray).Len
->(*byteArray).Len
(同上)(*ByteArray).Clear
->(*byteArray).clear
(*ByteArray).Slice
->(*byteArray).slice
(*ByteArray).Append
->(*byteArray).append
(*Writer).AddLine
->(*Writer).addLine
(*Writer).Line
->(*Writer).line
(*Writer).Dump
->(*Writer).dump
(*Writer).Write0
->(*Writer).write0
(*Writer).WritePadding
->(*Writer).writePadding
(*Writer).WriteLines
->(*Writer).writeLines
(*Writer).Format
->(*Writer).format
(*Writer).Append
->(*Writer).append
これらのメソッドは、tabwriter.Writer
やbyteArray
の内部的な処理を担うものであり、パッケージの外部から直接呼び出されることを意図していません。そのため、小文字で始まる名前に変更され、内部実装の詳細として隠蔽されました。
-
グローバル変数/関数名の変更:
Newline
->newline
UnicodeLen
->unicodeLen
Write
(テストヘルパー関数) ->write
Verify
(テストヘルパー関数) ->verify
Check
(テストヘルパー関数) ->check
Newline
は内部で使用されるバイトスライス定数であり、UnicodeLen
は内部的な文字幅計算に使用されるヘルパー関数です。これらも外部に公開する必要がないため、アンエクスポートされました。テストファイル内のヘルパー関数も同様に、テストスイートの外部から呼び出されることを意図していないため、アンエクスポートされています。
この変更により、tabwriter
パッケージの公開APIはより明確になり、パッケージの利用者は tabwriter.Writer
型とその Init
および Flush
メソッド、そして io.Writer
インターフェースの実装にのみ焦点を当てればよくなりました。内部的な byteArray
や addLine
といった詳細は隠蔽され、パッケージの内部構造が変更されても、外部のコードに影響を与えにくくなりました。
コアとなるコードの変更箇所
src/lib/tabwriter/tabwriter.go
ByteArray
型がbyteArray
に変更。ByteArray
型のメソッドInit
,Len
,Clear
,Slice
,Append
が、byteArray
型のメソッドとして、clear
,slice
,append
に変更(Init
とLen
は大文字のまま)。Writer
型のフィールドbuf
の型がByteArray
からbyteArray
に変更。Writer
型のメソッドAddLine
,Line
,Dump
,Write0
,WritePadding
,WriteLines
,Format
,Append
が、それぞれaddLine
,line
,dump
,write0
,writePadding
,writeLines
,format
,append
に変更。- グローバル変数
Newline
がnewline
に変更。 - 関数
UnicodeLen
がunicodeLen
に変更。 Flush
メソッド内で呼び出されるb.Format
がb.format
に、b.buf.Clear
がb.buf.clear
に、b.AddLine
がb.addLine
に変更。Append
メソッド内で呼び出されるb.Append
がb.append
に、UnicodeLen
がunicodeLen
に、b.buf.Slice
がb.buf.slice
に、b.Line
がb.line
に、b.AddLine
がb.addLine
に変更。
src/lib/tabwriter/tabwriter_test.go
Buffer
型がbuffer
に変更。Buffer
型のメソッドInit
,Clear
が、buffer
型のメソッドとしてinit
,clear
に変更。Write
関数がwrite
に変更。Verify
関数がverify
に変更。Check
関数がcheck
に変更。- テストケース内で呼び出される
Check
がcheck
に変更。 - テストヘルパー関数内で呼び出される
b.Clear
がb.clear
に、Write
がwrite
に、Verify
がverify
に変更。
コアとなるコードの解説
このコミットの核心は、Go言語の識別子の可視性ルールを tabwriter
パッケージに適用したことです。
例えば、src/lib/tabwriter/tabwriter.go
の以下の変更を見てみましょう。
--- a/src/lib/tabwriter/tabwriter.go
+++ b/src/lib/tabwriter/tabwriter.go
@@ -13,34 +13,34 @@ import (
// ----------------------------------------------------------------------------
-// Basic ByteArray support
+// Basic byteArray support
-type ByteArray struct {
+type byteArray struct {
a []byte;
}
-func (b *ByteArray) Init(initial_size int) {
+func (b *byteArray) Init(initial_size int) {
b.a = make([]byte, initial_size)[0 : 0];
}
-func (b *ByteArray) Len() int {
+func (b *byteArray) Len() int {
return len(b.a);
}
-func (b *ByteArray) Clear() {
+func (b *byteArray) clear() {
b.a = b.a[0 : 0];
}
-func (b *ByteArray) Slice(i, j int) []byte {
+func (b *byteArray) slice(i, j int) []byte {
return b.a[i : j]; // BUG should really be &b.a[i : j]
}
-func (b *ByteArray) Append(s []byte) {
+func (b *byteArray) append(s []byte) {
a := b.a;
n := len(a);
m := n + len(s);
ここでは、ByteArray
型が byteArray
にリネームされ、それに伴いそのメソッドの一部(Clear
, Slice
, Append
)も小文字で始まる名前に変更されています。Init
と Len
は大文字のままですが、これは tabwriter.Writer
の内部でこれらのメソッドが呼び出されるため、Goの初期段階では内部的な型であっても一部のメソッドはエクスポートされたままにする慣習があったか、あるいは特定のインターフェースを満たすためにエクスポートが必要だった可能性が考えられます。しかし、Clear
, Slice
, Append
は明らかに内部的なヘルパーメソッドであり、外部から直接アクセスされるべきではないため、アンエクスポートされています。
同様に、Writer
型の多くの内部ヘルパーメソッドもアンエクスポートされています。
--- a/src/lib/tabwriter/tabwriter.go
+++ b/src/lib/tabwriter/tabwriter.go
@@ -138,7 +138,7 @@ export type Writer struct {
// buf start of incomplete cell pos
-func (b *Writer) AddLine() {
+func (b *Writer) addLine() {
b.lines_size.Push(array.NewIntArray(0));
b.lines_width.Push(array.NewIntArray(0));
}
AddLine
が addLine
に変更されたことで、このメソッドは tabwriter
パッケージの内部でのみ使用されるようになります。これにより、パッケージの外部から tabwriter.Writer
オブジェクトの addLine
メソッドを呼び出すことはできなくなり、APIの利用者は tabwriter
の内部実装の詳細に触れることなく、より高レベルな Write
や Flush
メソッドを通じて機能を利用するようになります。
この変更は、Go言語の標準ライブラリ全体で一貫したAPI設計原則を確立する上で重要なステップでした。パッケージの内部構造と外部に公開されるAPIを明確に区別することで、ライブラリの安定性、保守性、そして使いやすさが向上します。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/
- Go言語のパッケージとモジュールに関するドキュメント: https://go.dev/doc/code
- Go言語のEffective Go (命名規則について): https://go.dev/doc/effective_go#names
text/tabwriter
パッケージのドキュメント: https://pkg.go.dev/text/tabwriter
参考にした情報源リンク
- Go言語のソースコードリポジトリ (GitHub): https://github.com/golang/go
- Go言語の初期のコミット履歴 (このコミットが含まれる): https://github.com/golang/go/commits/master?after=e28692f07d6b476ff9c684577cf11877fdb8991d+1
- Go言語の設計に関する議論 (Go Mailing Listなど、当時の情報源)
- Go言語の初期の設計に関する議論は、主にGoのメーリングリストや初期のGoブログで行われていました。具体的なリンクを特定するのは困難ですが、Goの設計原則に関する情報は、Effective GoやGoの公式ブログ記事に集約されています。