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

[インデックス 12637] ファイルの概要

このコミットは、Go言語の標準ライブラリgo/buildパッケージ内のImport関数の引数名をsrcからsrcDirへ変更するリファクタリングです。これにより、引数の意図がより明確になり、コードの可読性が向上します。

コミット

go/build: Import関数の引数名をより明確に (src -> srcDir)

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/036731c170e4d3b5458ad156b52e76611fd3d13c

元コミット内容

commit 036731c170e4d3b5458ad156b52e76611fd3d13c
Author: Robert Griesemer <gri@golang.org>
Date:   Wed Mar 14 13:19:14 2012 -0700

    go/build: clearer argument name for Import (src -> srcDir)
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/5820052

変更の背景

この変更の背景には、コードの可読性と保守性の向上が挙げられます。go/buildパッケージのImport関数は、Goパッケージのインポートパスに関する詳細を返す重要な関数です。この関数には、ローカルインポートパスを解釈するための基準となるディレクトリを指定する引数がありました。元々はsrcという名前でしたが、これは「ソースコード」全般を指すような曖昧さがありました。

しかし、この引数が実際に意味するのは、ローカルインポートパスが相対的に解決される「ソースディレクトリ」です。srcという名前では、この引数が単なるソース文字列なのか、それとも特定のディレクトリパスを指すのかが直感的に理解しにくいという問題がありました。

そこで、引数名をsrcDirに変更することで、その役割が「ソースディレクトリ」であることが明確になり、関数の利用者が引数の意図を誤解する可能性を減らすことができます。これは、Go言語の設計哲学である「明確さ」と「シンプルさ」に合致する変更と言えます。

前提知識の解説

Go言語のgo/buildパッケージ

go/buildパッケージは、Go言語のソースコードを解析し、パッケージのビルドに関する情報を提供する標準ライブラリです。このパッケージは、Goツールチェイン(go build, go installなど)の基盤となっており、Goのソースファイルやパッケージの構造を理解するために使用されます。

主な機能としては、以下のようなものがあります。

  • パッケージの解決: インポートパスに基づいて、対応するGoパッケージのディレクトリを特定します。
  • パッケージ情報の取得: パッケージ内のGoファイル、C/C++ファイル、アセンブリファイル、テストファイルなどの情報を収集します。
  • ビルドタグの処理: ビルドタグ(例: // +build linux,amd64)を解釈し、特定の環境向けのコードを識別します。
  • ローカルインポートパスの処理: 相対パスで指定されたインポートパスを絶対パスに解決します。

Import関数

go/buildパッケージのImport関数は、指定されたインポートパスに対応するGoパッケージの詳細情報(*Package構造体)を返します。この関数は、特にローカルインポートパス(例: ./mypackage)を扱う際に重要です。

Import関数のシグネチャは以下のようになっています(変更前)。

func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package, error)
  • path: インポートパス(例: "fmt", "./mypackage", "github.com/user/repo/pkg")。
  • src: ローカルインポートパスを解決するための基準となるディレクトリパス。この引数が今回の変更の対象です。
  • mode: インポートモード。パッケージの解析方法を制御します(例: ImportCommentImportDepsなど)。

Go言語のインポートパス

Go言語には、主に以下の2種類のインポートパスがあります。

  1. 標準インポートパス: fmt, net/httpのように、Goの標準ライブラリやGo Modulesによって解決されるパス。
  2. ローカルインポートパス: ./, ../などで始まる相対パス。これらは、現在のファイルまたは指定された基準ディレクトリからの相対位置でパッケージを指定します。例えば、./mypackageは、現在のディレクトリのサブディレクトリmypackageをインポートすることを意味します。

Import関数におけるsrc(変更後はsrcDir)引数は、このローカルインポートパスを解決する際に、どのディレクトリを基準とするかを指定するために使用されます。

技術的詳細

このコミットの技術的詳細は、Go言語のgo/buildパッケージにおけるImport関数の引数名の変更に集約されます。

変更前:

func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package, error)

変更後:

func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error)

そして、この変更に伴い、関数内部およびgo/buildパッケージのトップレベルのImport関数の呼び出し箇所で、srcという変数名がsrcDirに置き換えられています。

この変更は、機能的な変更を一切伴いません。つまり、関数の振る舞いや出力結果は変更前後で全く同じです。これは純粋なリファクタリングであり、コードのセマンティクス(意味)をより正確に反映させることを目的としています。

なぜsrcが曖昧だったのかというと、プログラミングの文脈において「src」という略語は多岐にわたる意味を持ち得るからです。例えば、「ソースコード(source code)」全体を指すこともあれば、「ソースファイル(source file)」を指すこともあります。しかし、このImport関数のsrc引数は、具体的に「ローカルインポートパスを解決するための基準となるディレクトリ」を指していました。

srcDirという新しい引数名は、この「ディレクトリ」という側面を明確に強調しています。これにより、関数を呼び出す開発者は、この引数にファイルパスではなく、ディレクトリパスを渡すべきであるということを直感的に理解できます。これは、APIの使いやすさ(Usability)と、将来的な誤用を防ぐための重要な改善です。

また、ドキュメンテーションコメントもsrcからsrcDirに更新されており、コードとドキュメントの一貫性が保たれています。これは、Go言語のコードベース全体で重視される品質基準の一つです。

このような小さなリファクタリングは、大規模なコードベースにおいて特に重要です。多数の開発者が関わるプロジェクトでは、引数名のような些細な部分でも曖昧さが残ると、誤解やバグの原因となる可能性があります。明確な命名規則は、コードベース全体の理解を深め、メンテナンスコストを削減する上で不可欠です。

コアとなるコードの変更箇所

変更はsrc/pkg/go/build/build.goファイルに集中しています。

具体的には、以下の部分が変更されています。

  1. Import関数のシグネチャの変更:

    --- a/src/pkg/go/build/build.go
    +++ b/src/pkg/go/build/build.go
    @@ -343,7 +343,7 @@ func (e *NoGoError) Error() string {
     // If an error occurs, Import returns a non-nil error also returns a non-nil
     // *Package containing partial information.
     //
    -func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package, error) {
    +func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) {
     	p := &Package{
     		ImportPath: path,
     	}
    
  2. Import関数内部での引数名の使用箇所の変更:

    --- a/src/pkg/go/build/build.go
    +++ b/src/pkg/go/build/build.go
    @@ -363,11 +363,11 @@ func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package,
     
     	binaryOnly := false
     	if IsLocalImport(path) {
    -		if src == "" {
    +		if srcDir == "" {
     			return p, fmt.Errorf("import %q: import relative to unknown directory", path)
     		}
     		if !ctxt.isAbsPath(path) {
    -			p.Dir = ctxt.joinPath(src, path)
    +			p.Dir = ctxt.joinPath(srcDir, path)
     		}
     		// Determine canonical import path, if any.
     		if ctxt.GOROOT != "" {
    
  3. トップレベルのImport関数のシグネチャと呼び出し箇所の変更:

    --- a/src/pkg/go/build/build.go
    +++ b/src/pkg/go/build/build.go
    @@ -640,8 +640,8 @@ func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.P
     }
     
     // Import is shorthand for Default.Import.
    -func Import(path, src string, mode ImportMode) (*Package, error) {
    -	return Default.Import(path, src, mode)
    +func Import(path, srcDir string, mode ImportMode) (*Package, error) {
    +	return Default.Import(path, srcDir, mode)
     }
     
     // ImportDir is shorthand for Default.ImportDir.
    
  4. ドキュメンテーションコメントの更新:

    --- a/src/pkg/go/build/build.go
    +++ b/src/pkg/go/build/build.go
    @@ -328,10 +328,10 @@ func (e *NoGoError) Error() string {
     }
     
     // Import returns details about the Go package named by the import path,
    -// interpreting local import paths relative to the src directory.  If the path
    -// is a local import path naming a package that can be imported using a
    -// standard import path, the returned package will set p.ImportPath to
    -// that path.
    +// interpreting local import paths relative to the srcDir directory.
    +// If the path is a local import path naming a package that can be imported
    +// using a standard import path, the returned package will set p.ImportPath
    +// to that path.
     //
     // In the directory containing the package, .go, .c, .h, and .s files are
     // considered part of the package except for:
    

コアとなるコードの解説

このコミットのコアとなる変更は、go/buildパッケージ内のImport関数の引数名srcsrcDirに変更したことです。

Import関数は、Goのパッケージをインポートする際に、そのパッケージに関する詳細情報を取得するために使用されます。特に、ローカルインポートパス(例: ./myutil)が指定された場合、このパスを解決するためには、どのディレクトリを基準とするかを知る必要があります。この基準となるディレクトリが、変更前のsrc引数、変更後のsrcDir引数によって指定されます。

変更前のsrcという名前は、その引数が「ソースコード」全般を指すのか、「ソースディレクトリ」を指すのかが曖昧でした。例えば、srcという名前から、単一のソースファイルパスを期待する開発者もいるかもしれません。しかし、この引数に期待されるのは、常にディレクトリのパスでした。

srcDirという新しい名前は、この引数が「ソースディレクトリ」であることを明確に示しています。これにより、関数を呼び出す開発者は、この引数にディレクトリのパスを渡すべきであるという意図をすぐに理解できます。

具体的にコードを見ると、Import関数内でローカルインポートパスが検出された場合(IsLocalImport(path))、srcDirが空文字列でないことを確認し、ctxt.joinPath(srcDir, path)を使って最終的なパッケージディレクトリp.Dirを構築しています。この処理は、srcDirがまさに基準となるディレクトリとして機能していることを示しています。

この変更は、Go言語のAPI設計における「明確さ」と「自己文書化」の原則を反映しています。引数名がその役割を正確に表現することで、外部ドキュメントを参照することなく、コードを読むだけで関数の意図を理解しやすくなります。これは、コードの保守性を高め、将来的なバグの発生を防ぐ上で非常に重要です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント: go/buildパッケージ (https://pkg.go.dev/go/build)
  • Go言語のインポートパスに関する一般的な情報