[インデックス 12016] ファイルの概要
このコミットは、Go言語の標準ライブラリにおけるgo/astパッケージからgo/docパッケージへのExampleコード抽出ロジックの移動に関するものです。具体的には、GoのソースコードからExample関数(ExampleFooのような形式で記述され、_test.goファイルに配置されることが多い)を解析し、その情報を提供する機能がgo/astからgo/docへと移管されました。これにより、Exampleコードの処理がより適切なパッケージに集約され、go/docパッケージの責務が明確化されました。
コミット
commit b6e2d6b778aa63d10db72feb3b03fb0becac38da
Author: Robert Griesemer <gri@golang.org>
Date: Fri Feb 17 12:00:12 2012 -0800
go/doc: move Example code from go/ast to go/doc.
Fixes #3048.
R=rsc
CC=golang-dev
https://golang.org/cl/5672081
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b6e2d6b778aa63d10db72feb3b03fb0becac38da
元コミット内容
このコミットの元の内容は、go/astパッケージに存在していたExampleコードを処理するロジックをgo/docパッケージに移動することです。これには、Example構造体、Examples関数、およびExampleの出力を解析する関連ヘルパー関数が含まれます。この移動に伴い、これらの機能を利用していたcmd/go(Goコマンドラインツール)やcmd/godoc(Goドキュメンテーションツール)などのコンシューマ側も、新しいgo/docパッケージのAPIを使用するように変更されています。
変更の背景
この変更の背景には、Go言語の標準ライブラリにおけるパッケージの責務の明確化があります。
- Issue #3048の解決: このコミットはGoのIssue #3048「
go/astshould not know aboutExamplefunctions」を修正します。このIssueでは、go/astパッケージがExample関数に関する知識を持つべきではないという点が指摘されていました。go/astパッケージはGoのソースコードの抽象構文木(AST)を表現するためのものであり、特定のドキュメンテーションやテストの慣習(Example関数など)に関するロジックを持つことは、その責務を超えていると考えられました。 go/docの責務の強化:go/docパッケージは、Goのソースコードからドキュメンテーションを生成するための情報(パッケージ、型、関数、変数、定数、そしてExample)を抽出する役割を担っています。Example関数は、Goのドキュメンテーションシステムにおいて非常に重要な要素であり、コードの動作例を示すために使用されます。したがって、Exampleコードの解析と抽出のロジックは、ASTの構造そのものよりも、ドキュメンテーション生成の文脈でより適切にgo/docパッケージに属すると判断されました。- コードの分離と保守性の向上: Exampleコードの処理ロジックを
go/astからgo/docに移動することで、各パッケージの関心事が分離され、コードベース全体の保守性と理解度が向上します。go/astは純粋なAST表現に集中し、go/docはドキュメンテーション関連の処理に集中できるようになります。
前提知識の解説
このコミットを理解するためには、以下のGo言語の概念とツールに関する知識が必要です。
- Go言語のパッケージシステム: Goのコードはパッケージに分割され、再利用可能なモジュールとして機能します。各パッケージは特定の責務を持ちます。
go/astパッケージ: Goのソースコードを解析して生成される抽象構文木(Abstract Syntax Tree: AST)を表現するためのデータ構造と関数を提供します。プログラミング言語のコンパイラやツールがコードを理解・操作する際の基盤となります。go/docパッケージ: GoのソースコードからドキュメンテーションコメントやExample関数などの情報を抽出し、構造化されたドキュメンテーションデータを生成するための機能を提供します。godocツールはこのパッケージを利用してドキュメンテーションを生成します。- GoのExample関数: Goでは、
func ExampleFoo()やfunc ExamplePackage_Method()のようにExampleプレフィックスを持つ関数を_test.goファイルに記述することで、コードの実行例を示すことができます。これらの関数はテストの一部として実行され、その出力が期待される出力と一致するか検証されます。また、godocツールによって自動的にドキュメンテーションに組み込まれ、ユーザーがコードの動作を理解するのに役立ちます。 godocツール: Go言語の公式ドキュメンテーションツールです。Goのソースコードからドキュメンテーションを抽出し、HTML形式で表示したり、コマンドラインで参照したりすることができます。Example関数もgodocによって表示されます。go testコマンド: Goのテストを実行するためのコマンドです。Example関数もgo testによって実行され、その出力が検証されます。src/cmd/dist/build.c: GoのツールチェインをビルドするためのC言語のスクリプトです。Goの標準ライブラリパッケージのビルド順序やクリーンアップ対象などを定義しています。go.mod/go.sum: Goモジュールシステムにおける依存関係管理ファイルです。このコミットが行われた2012年時点ではGoモジュールは存在せず、Goのビルドシステムは異なる方法で依存関係を管理していました。しかし、概念としてはパッケージ間の依存関係を管理する仕組みが存在していました。
技術的詳細
このコミットの技術的詳細は、主に以下の点に集約されます。
- ファイルのリネームとパッケージ名の変更:
src/pkg/go/ast/example.goがsrc/pkg/go/doc/example.goにリネームされました。- これにより、ファイル内のパッケージ宣言が
package astからpackage docに変更されました。
- 型定義の移動と修飾:
go/astパッケージに存在していたExample構造体(Example関数のメタデータを保持)がgo/docパッケージに移動しました。Example構造体内のフィールド(Code,Comments)や、Examples関数、exampleOutput関数が引数として受け取る型(File,GenDecl,FuncDecl,CommentGroup)は、元々go/astパッケージ内で定義されていました。これらがgo/docパッケージに移動したことで、これらの型を参照する際にはast.Node,ast.CommentGroup,ast.File,ast.GenDecl,ast.FuncDeclのように明示的にastパッケージを修飾する必要が生じました。
- 依存関係の更新:
src/pkg/go/doc/example.go(旧src/pkg/go/ast/example.go)は、go/astパッケージの型を使用するため、新たにimport "go/ast"が追加されました。src/cmd/go/test.goとsrc/cmd/godoc/godoc.goは、Example関数を処理するためにgo/ast.Examplesではなくgo/doc.Examplesを使用するように変更されました。これに伴い、これらのファイルでもimport "go/doc"が追加されています。src/cmd/dist/build.cでは、ビルド順序とクリーンアップ対象にpkg/go/docが追加されました。これは、go/docパッケージがGoのビルドシステムにおいて重要なコンポーネントとして認識され、適切にビルドおよび管理される必要があることを示しています。
- APIの変更:
ast.Examples関数は削除され、代わりにdoc.Examples関数が提供されるようになりました。この関数は、*ast.Fileのスライスを受け取り、*doc.Exampleのスライスを返します。godocツール内のexample_htmlFunc関数やPageInfo構造体、getPageInfo関数など、Example情報を扱う部分の型シグネチャが*ast.Exampleから*doc.Exampleに変更されました。
この変更は、Goのツールチェイン内部のアーキテクチャを改善し、各コンポーネントの責務をより明確にするための重要なステップでした。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は以下のファイルに集中しています。
-
src/pkg/go/{ast => doc}/example.go(ファイルのリネームと内容変更):src/pkg/go/ast/example.goからsrc/pkg/go/doc/example.goへのファイル名変更。- パッケージ宣言が
package astからpackage docへ変更。 import "go/ast"の追加。Example構造体内のCode、Commentsフィールドの型がNode、*CommentGroupからast.Node、*ast.CommentGroupへ変更。Examples関数の引数files ...*Fileがfiles ...*ast.Fileへ変更。- 関数内部で参照される
GenDecl、FuncDecl、CommentGroupなどの型がast.GenDecl、ast.FuncDecl、ast.CommentGroupへ変更。
-
src/cmd/go/test.go:import "go/doc"の追加。ast.Examples(f)の呼び出しがdoc.Examples(f)へ変更。
-
src/cmd/godoc/godoc.go:example_htmlFunc関数の引数examples []*ast.Exampleがexamples []*doc.Exampleへ変更。PageInfo構造体のExamples []*ast.ExampleがExamples []*doc.Exampleへ変更。getPageInfo関数内でexamples []*ast.Exampleの宣言がexamples []*doc.Exampleへ変更。ast.Examples(files...)の呼び出しがdoc.Examples(files...)へ変更。
-
src/cmd/dist/build.c:buildorder配列に"pkg/go/doc"を追加。cleantab配列に"pkg/go/doc"を追加。
コアとなるコードの解説
src/pkg/go/{ast => doc}/example.go の変更
このファイルは、Example関数を解析し、その構造を表現するExample型と、ファイルからExampleを抽出するExamples関数を定義しています。
変更前 (package ast):
package ast
type Example struct {
Name string // name of the item being exemplified
Doc string // example function doc string
Code Node
Comments []*CommentGroup
Output string // expected output
}
func Examples(files ...*File) []*Example { ... }
CodeやCommentsの型、Examples関数の引数*Fileは、同じastパッケージ内で定義されている型を参照していました。
変更後 (package doc):
package doc
import (
"go/ast" // astパッケージをインポート
"go/token"
"regexp"
"sort"
)
type Example struct {
Name string // name of the item being exemplified
Doc string // example function doc string
Code ast.Node // ast.Nodeに明示的に変更
Comments []*ast.CommentGroup // ast.CommentGroupに明示的に変更
Output string // expected output
}
func Examples(files ...*ast.File) []*Example { // 引数もast.Fileに明示的に変更
var list []*Example
for _, file := range files {
// ...
if g, ok := decl.(*ast.GenDecl); ok && g.Tok != token.IMPORT { // ast.GenDeclに明示的に変更
// ...
}
f, ok := decl.(*ast.FuncDecl) // ast.FuncDeclに明示的に変更
if !ok {
continue
}
// ...
}
// ...
}
func exampleOutput(fun *ast.FuncDecl, comments []*ast.CommentGroup) string { // ast.FuncDecl, ast.CommentGroupに明示的に変更
// ...
var last *ast.CommentGroup // ast.CommentGroupに明示的に変更
// ...
}
この変更により、Example構造体やExamples関数はgo/docパッケージの一部となりました。しかし、Example関数の解析には依然としてASTの構造(ast.Node, ast.File, ast.FuncDeclなど)が必要なため、go/astパッケージをインポートし、これらの型をast.で修飾して使用するようになりました。これは、Exampleの抽出ロジックがASTの知識に依存しつつも、そのロジック自体はドキュメンテーション生成の責務を持つgo/docに属するという、より適切な分離を示しています。
src/cmd/go/test.go と src/cmd/godoc/godoc.go の変更
これらのファイルは、Example関数を実際に利用するツール(go testとgodoc)のコードです。
変更前:
// src/cmd/go/test.go
import (
// ...
"go/ast"
// ...
)
// ...
for _, e := range ast.Examples(f) { // astパッケージのExamples関数を呼び出し
// ...
}
// src/cmd/godoc/godoc.go
import (
// ...
"go/ast"
// ...
)
// ...
func example_htmlFunc(funcName string, examples []*ast.Example, fset *token.FileSet) string { // ast.Example型を使用
// ...
}
// ...
examples = append(examples, ast.Examples(files...)...) // astパッケージのExamples関数を呼び出し
変更後:
// src/cmd/go/test.go
import (
// ...
"go/ast"
"go/doc" // docパッケージをインポート
// ...
)
// ...
for _, e := range doc.Examples(f) { // docパッケージのExamples関数を呼び出し
// ...
}
// src/cmd/godoc/godoc.go
import (
// ...
"go/ast"
"go/doc" // docパッケージをインポート
// ...
)
// ...
func example_htmlFunc(funcName string, examples []*doc.Example, fset *token.FileSet) string { // doc.Example型を使用
// ...
}
// ...
examples = append(examples, doc.Examples(files...)...) // docパッケージのExamples関数を呼び出し
これらの変更は、Exampleコードの抽出ロジックがgo/astからgo/docへ移動したことに伴う、API利用箇所の更新です。これにより、go testやgodocは、Exampleに関する情報を取得する際に、より高レベルな抽象化を提供するgo/docパッケージを利用するようになりました。
src/cmd/dist/build.c の変更
このファイルはGoのビルドシステムの一部であり、Goの標準ライブラリパッケージのビルド順序やクリーンアップ対象を定義しています。
変更前: go/docは明示的にリストされていませんでした。
変更後:
static char *buildorder[] = {
// ...
"pkg/text/template",
"pkg/go/doc", // 追加
"cmd/go",
};
static char *cleantab[] = {
// ...
"pkg/go/build",
"pkg/go/doc", // 追加
"pkg/go/parser",
// ...
};
pkg/go/docがbuildorderとcleantabに追加されたことで、go/docパッケージがGoのビルドプロセスにおいて正式なビルド対象およびクリーンアップ対象として認識されるようになりました。これは、go/docがExampleコードの処理という重要な機能を担うようになったため、そのビルドと管理が適切に行われる必要があることを示しています。
関連リンク
- Go Issue #3048: https://github.com/golang/go/issues/3048
- Go Change-ID 5672081: https://golang.org/cl/5672081 (Gerritの変更履歴)
- Go言語の
go/astパッケージドキュメンテーション (現在のもの): https://pkg.go.dev/go/ast - Go言語の
go/docパッケージドキュメンテーション (現在のもの): https://pkg.go.dev/go/doc - Go言語のExample関数に関する公式ブログ記事 (Go 1.0リリース時のもの): https://go.dev/blog/go1.0 (Example関数に関する記述が含まれる可能性があります)
参考にした情報源リンク
- Go Issue #3048の議論内容
- Go言語の公式ドキュメンテーション(
go/astおよびgo/docパッケージ) - Go言語のソースコード(コミット前後の差分)
- Go言語のExample関数に関する一般的な知識
godocツールの機能に関する知識go testコマンドの機能に関する知識- Go言語のビルドシステムに関する一般的な知識
- Go言語の歴史と進化に関する情報