[インデックス 11401] ファイルの概要
このコミットは、Go言語の標準ライブラリである go/doc
パッケージにおけるAPIの変更を元に戻し、クリーンアップを行うものです。特に、メソッドの表現方法に関する以前の設計判断を修正し、Func
型にメソッド固有の情報を統合することで、APIの使いやすさとコードの可読性を向上させています。
コミット
commit d571c5ca78a58489a1fd223dd6749a650668ccdc
Author: Robert Griesemer <gri@golang.org>
Date: Wed Jan 25 16:48:06 2012 -0800
go/doc: revert API change (per former discussion) and cleanup
Separating Method from Func made the code only more complicated
without adding much to the useability/readability of the API.
Reverted to where it was, but leaving the new method-specific
fields Orig and Level.
Former clients (godoc) of doc.Method only used the Func fields;
and because Func was embedded, no changes are needed with respect
to the removal of Method.
Changed type of Func.Recv from ast.Expr to string. This was a
long-standing TODO. Also implemented Func.Orig field (another TODO).
No further go/doc API changes are expected for Go 1.
R=rsc, r, r
CC=golang-dev
https://golang.org/cl/5577043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d571c5ca78a58489a1fd223dd6749a650668ccdc
元コミット内容
このコミットは、go/doc
パッケージにおいて、関数とメソッドを区別するために導入された Method
型を廃止し、以前の状態に戻すものです。以前の変更では、メソッドをより詳細に記述するために Method
型が導入されましたが、結果としてコードが複雑になり、APIの使いやすさや可読性に大きなメリットをもたらさなかったと判断されました。
具体的には、以下の変更が行われています。
Method
型の削除。Func
型に、メソッド固有のフィールドであるOrig
(元のレシーバ型) とLevel
(埋め込みレベル) を残しつつ、メソッドの情報を統合。Func.Recv
フィールドの型をast.Expr
からstring
に変更。これは以前からのTODO(課題)でした。Func.Orig
フィールドの実装。これも以前からのTODOでした。
この変更により、go/doc
パッケージのAPIは簡素化され、Go 1リリースに向けてこれ以上のAPI変更は予定されていないことが示されています。
変更の背景
このコミットの背景には、go/doc
パッケージのAPI設計に関する議論と、Go 1リリースに向けたAPIの安定化という目標があります。
当初、go/doc
パッケージでは、関数とメソッドを区別するために Func
と Method
という異なる型を導入する試みがありました。これは、メソッドがレシーバを持つという特性をAPIレベルで明確に表現するためと考えられます。しかし、コミットメッセージにあるように、「Method
を Func
から分離したことで、コードはより複雑になっただけで、APIの使いやすさや可読性に大きなメリットをもたらさなかった」という結論に至りました。
godoc
のような既存のクライアントは、doc.Method
の Func
フィールドのみを使用しており、Func
が埋め込まれていたため、Method
の削除によっても大きな変更は不要でした。このことは、Method
型の分離が実用上あまり意味がなかったことを示唆しています。
また、Func.Recv
の型が ast.Expr
であったことや、Func.Orig
フィールドが未実装であったことは、以前からの「TODO」(課題)として認識されていました。ast.Expr
は抽象構文木における一般的な式を表す型であり、レシーバの型を文字列として直接扱う方が、ドキュメント生成の文脈ではよりシンプルで扱いやすいと判断されたのでしょう。
Go 1のリリースが迫る中で、APIの安定性と簡潔性は非常に重要でした。このコミットは、複雑さを減らし、より直感的で使いやすいAPIに回帰することで、go/doc
パッケージをGo 1の標準として確立するための最終調整の一環として行われました。
前提知識の解説
このコミットを理解するためには、以下のGo言語および関連ツールの基本的な知識が必要です。
-
Go言語の関数とメソッド:
- 関数 (Function): 特定のタスクを実行するコードブロック。レシーバを持ちません。
- メソッド (Method): 特定の型に関連付けられた関数。レシーバ(
func (r Type) MethodName(...)
のr Type
の部分)を持ち、その型の値に対して呼び出されます。Goでは、構造体だけでなく、任意の型にメソッドを定義できます。
-
Goの抽象構文木 (AST):
- Goコンパイラは、ソースコードを解析して抽象構文木(AST)を生成します。ASTは、プログラムの構造を木構造で表現したものです。
go/ast
パッケージは、GoのソースコードのASTを操作するための機能を提供します。ast.Expr
: ASTにおける式を表すインターフェース型。変数、リテラル、関数呼び出し、型など、様々な種類の式が含まれます。ast.FuncDecl
: 関数またはメソッドの宣言を表すASTノード。ast.FieldList
: 関数のパラメータや結果、メソッドのレシーバなどを表すフィールドのリスト。ast.StarExpr
: ポインタ型(例:*T
)を表すASTノード。ast.Ident
: 識別子(変数名、型名など)を表すASTノード。
-
go/doc
パッケージ:- Goの標準ライブラリの一部で、Goのソースコードからパッケージ、型、関数、メソッドなどのドキュメントを抽出・生成するためのパッケージです。
godoc
コマンドやGoの公式ドキュメントサイト(pkg.go.devなど)は、このgo/doc
パッケージを利用してドキュメントを生成しています。- このパッケージは、
go/ast
パッケージで解析されたASTを受け取り、それをより高レベルなドキュメント構造に変換します。
-
埋め込み (Embedding) とメソッドの継承:
- Goでは、構造体の中に別の構造体やインターフェースを「埋め込む」ことができます。これにより、埋め込まれた型のフィールドやメソッドが、埋め込み元の型に「昇格」され、直接アクセスできるようになります。
- メソッドの埋め込みは、コードの再利用性を高める強力なメカニズムです。
go/doc
パッケージは、この埋め込みによって継承されたメソッドも適切にドキュメント化する必要があります。
-
Go 1の安定化:
- Go 1は、Go言語の最初の安定版リリースであり、その後のGo言語の互換性保証の基盤となりました。Go 1リリース前には、APIの最終的な調整と安定化が活発に行われていました。このコミットもその一環です。
これらの知識があることで、コミットがなぜ行われたのか、そしてそれがGo言語のドキュメント生成システムにどのような影響を与えるのかを深く理解することができます。
技術的詳細
このコミットの技術的詳細は、主に go/doc
パッケージ内部のデータ構造と処理ロジックの変更に集約されます。
-
Method
型の廃止とFunc
型への統合:- 以前は、
src/pkg/go/doc/doc.go
にMethod
という構造体が存在し、これは*Func
を埋め込んでいました。つまり、メソッドはFunc
のすべてのフィールドを持ち、さらにメソッド固有のフィールド(Origin
やLevel
)を追加で持つ設計でした。 - このコミットでは、
Method
型が完全に削除されました。 - 代わりに、
Type
構造体のMethods
フィールドの型が[]*Method
から[]*Func
に変更されました。これは、メソッドがもはや独立したMethod
型として表現されず、Func
型のインスタンスとして扱われることを意味します。 Func
構造体には、メソッド固有の情報を格納するための新しいフィールドが追加されました。Recv string
: メソッドのレシーバの型を文字列で表現します(例:"T"
や"*T"
)。Orig string
: 埋め込みメソッドの場合、そのメソッドが元々定義されていたレシーバの型を文字列で表現します。Level int
: 埋め込みの深さを示します。0は埋め込みではないことを意味します。
- 以前は、
-
Func.Recv
の型変更 (ast.Expr
からstring
へ):- 以前の
Func
構造体では、Recv
フィールドはast.Expr
型でした。これは、レシーバの型がASTノードとして直接保持されていたことを意味します。 - このコミットでは、
Recv
の型がstring
に変更されました。これにより、レシーバの型情報を文字列として直接扱うことができ、ドキュメント生成の際にASTを再解析する必要がなくなります。 - この変更に伴い、
src/pkg/go/doc/reader.go
にrecvString(recv ast.Expr) string
というヘルパー関数が追加されました。この関数は、ast.Expr
型のレシーバを受け取り、それを"T"
や"*T"
のような文字列形式に変換する役割を担います。これにより、ASTの複雑さを抽象化し、Func
型のRecv
フィールドに簡潔な文字列を格納できるようになりました。
- 以前の
-
メソッドセットの処理ロジックの変更:
src/pkg/go/doc/reader.go
内のmethodSet
型は、以前はmap[string]*Method
でしたが、このコミットでmap[string]*Func
に変更されました。これは、メソッドがFunc
型として直接管理されるようになったことを反映しています。methodSet.set
およびmethodSet.add
メソッドのロジックも、Method
型の代わりにFunc
型を直接操作するように修正されました。特に、メソッドの衝突解決(同じ名前のメソッドが異なる埋め込みレベルで存在する場合など)のロジックもFunc
型に基づいて調整されています。customizeRecv
関数も、*Method
を受け取って*Method
を返す代わりに、*Func
を受け取って*Func
を返すように変更されました。この関数は、埋め込みメソッドのレシーバ情報を調整するために使用されます。
-
フィルタリングロジックの簡素化:
src/pkg/go/doc/filter.go
に存在したfilterMethods
関数が削除されました。Type
構造体のMethods
フィールドが[]*Func
になったため、メソッドのフィルタリングもfilterFuncs
関数で統一的に処理できるようになりました。これにより、コードの重複が排除され、簡潔性が向上しました。
これらの変更は、go/doc
パッケージの内部構造を簡素化し、メソッドの表現をより効率的かつ統一的に行うことを目的としています。特に、ast.Expr
から string
への変更は、ドキュメント生成のパフォーマンスとコードの保守性にも寄与すると考えられます。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は以下のファイルに集中しています。
-
src/pkg/go/doc/doc.go
:Method
構造体の定義が削除されました。Type
構造体のMethods
フィールドの型が[]*Method
から[]*Func
に変更されました。Func
構造体に以下のフィールドが追加されました。type Func struct { Doc string Name string Decl *ast.FuncDecl // methods // (for functions, these fields have the respective zero value) Recv string // actual receiver "T" or "*T" Orig string // original receiver "T" or "*T" Level int // embedding level; 0 means not embedded }
-
src/pkg/go/doc/filter.go
:filterMethods
関数が削除されました。filterTypes
関数内で、td.Methods = filterMethods(td.Methods, f)
の呼び出しがtd.Methods = filterFuncs(td.Methods, f)
に変更されました。
-
src/pkg/go/doc/reader.go
:methodSet
型の定義がtype methodSet map[string]*Method
からtype methodSet map[string]*Func
に変更されました。recvString(recv ast.Expr) string
ヘルパー関数が追加されました。methodSet.set
メソッド内で、Method
型のインスタンスを生成していた部分がFunc
型のインスタンスを生成するように変更され、Recv
,Orig
フィールドが設定されるようになりました。methodSet.add
メソッドの引数と内部ロジックが*Method
から*Func
に変更されました。sortedFuncs
とsortedMethods
のロジックが統合され、sortedFuncs
がメソッドも処理するように変更されました。customizeRecv
関数の引数と戻り値の型が*Method
から*Func
に変更され、内部でFunc
型のフィールドを直接操作するように修正されました。
これらの変更は、go/doc
パッケージのデータモデルと、そのデータモデルを操作するロジックの根本的な変更を示しています。
コアとなるコードの解説
src/pkg/go/doc/doc.go
の変更
このファイルは、go/doc
パッケージが公開する主要なデータ構造を定義しています。
Method
型の削除は、メソッドを独立したエンティティとして扱うのではなく、関数の一種としてFunc
型で表現するという設計思想への回帰を示しています。Type
構造体のMethods
フィールドが[]*Func
になったことで、型が持つメソッドのリストは、通常の関数と同じFunc
型のポインタの配列として扱われるようになりました。Func
構造体へのRecv
,Orig
,Level
フィールドの追加は、メソッド固有の情報をFunc
型自体が保持できるようにするためのものです。Recv
: メソッドのレシーバの型(例:MyType
や*MyType
)を文字列で保持します。これは、ドキュメント表示の際に直接利用できる形式です。Orig
: 埋め込みによって「継承」されたメソッドの場合、そのメソッドが元々定義されていたレシーバの型を保持します。これにより、メソッドの出自を追跡できます。Level
: 埋め込みの深さを示します。0は直接定義されたメソッド、1は1段階埋め込まれた型から継承されたメソッド、といった具合です。これにより、メソッドの「近さ」を判断できます。
src/pkg/go/doc/filter.go
の変更
このファイルは、ドキュメント要素をフィルタリングするための関数を提供します。
filterMethods
の削除とfilterFuncs
への統合は、Method
型が廃止され、メソッドがFunc
型として扱われるようになった結果です。これにより、関数とメソッドのフィルタリングロジックが統一され、コードの重複が排除されました。これは、APIの簡素化と内部実装の整合性向上に貢献します。
src/pkg/go/doc/reader.go
の変更
このファイルは、GoのASTを読み込み、go/doc
パッケージのデータ構造に変換する主要なロジックを含んでいます。
methodSet
の型がmap[string]*Func
に変更されたことは、内部でメソッドを管理する際にもFunc
型を直接使用するようになったことを意味します。これにより、Method
型を介した間接的な処理が不要になり、コードが簡素化されます。recvString
ヘルパー関数の導入は、Func.Recv
をstring
型にするための重要な変更です。この関数は、ast.Expr
型のレシーバ(ASTノード)を受け取り、それを人間が読める文字列形式(例:"T"
や"*T"
)に変換します。これにより、ASTの複雑な構造を直接扱う必要がなくなり、Func
型のデータがよりシンプルになります。methodSet.set
およびmethodSet.add
メソッドの変更は、ASTから読み取った関数やメソッドの情報をFunc
型のインスタンスとしてmethodSet
に追加するロジックを反映しています。特に、Func
型のRecv
,Orig
,Level
フィールドがここで適切に設定されるようになります。customizeRecv
関数の変更は、埋め込みメソッドのレシーバ情報を調整する際に、Func
型のインスタンスを直接操作するようにしたものです。これにより、Method
型を介した変換が不要になり、処理が直接的になります。
これらの変更は、go/doc
パッケージがGoのソースコードからドキュメント情報を抽出し、内部で表現する方法を根本的に見直した結果であり、APIの簡素化と内部実装の効率化を両立させています。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
go/doc
パッケージのドキュメント: https://pkg.go.dev/go/docgo/ast
パッケージのドキュメント: https://pkg.go.dev/go/ast- このコミットが参照している Go CL (Change List): https://golang.org/cl/5577043 (現在はGoのGerritにリダイレクトされます)
参考にした情報源リンク
- コミットメッセージと差分 (
git diff
) - Go言語の公式ドキュメント (
go/doc
,go/ast
パッケージの解説) - Go言語のソースコード (
src/pkg/go/doc/
) - Go言語の歴史に関する一般的な知識 (Go 1の安定化プロセスなど)