[インデックス 15139] ファイルの概要
このコミットは、Go言語の標準ライブラリ archive/tar パッケージ内の common.go ファイルに対する変更です。具体的には、FileInfoHeader 関数におけるファイルタイプのチェック方法を、より簡潔でGoらしいイディオムに修正しています。
コミット
commit e7fe1944acb96de2fce832c11a1577a9e8e7a80a
Author: David Symonds <dsymonds@golang.org>
Date: Tue Feb 5 15:39:55 2013 +1100
archive/tar: small simplification using FileMode.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/7305043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e7fe1944acb96de2fce832c11a1577a9e8e7a80a
元コミット内容
archive/tar: small simplification using FileMode.
このコミットは、archive/tar パッケージにおいて、os.FileMode を使用してコードをわずかに簡素化することを目的としています。
変更の背景
この変更の背景には、Go言語の標準ライブラリにおけるコードの可読性とイディオムの改善があります。以前のコードでは、ファイルのタイプが通常のファイルであるかどうかを判断するために、ビット演算子 (&) と os.ModeType 定数を使用していました。これは機能的には正しいものの、os.FileMode 型が提供するよりセマンティックなメソッド IsRegular() を使用することで、コードがより明確になり、意図が伝わりやすくなります。
Go言語では、APIが提供する専用のメソッドがある場合、それを使用することが推奨されます。これにより、コードの意図がより明確になり、将来的なAPIの変更にも強くなります。このコミットは、このようなGoの設計思想に沿った、小さな改善であり、コードベース全体の品質向上に貢献しています。
前提知識の解説
このコミットを理解するためには、Go言語の os パッケージ、特に os.FileInfo と os.FileMode 型に関する知識が必要です。
-
os.FileInfoインターフェース:os.FileInfoは、ファイルに関する情報(名前、サイズ、パーミッション、最終更新時刻など)を提供するインターフェースです。os.Statやos.Lstatなどの関数がこのインターフェースを実装した値を返します。 このインターフェースには、ファイルのモード(パーミッションとファイルタイプ)を返すMode() os.FileModeメソッドが含まれています。 -
os.FileMode型:os.FileModeは、ファイルのパーミッションとファイルタイプ(ディレクトリ、シンボリックリンク、通常のファイルなど)を表すビットフラグの集合です。これはuint32のエイリアスとして定義されています。 -
os.ModeType定数:os.ModeTypeはos.FileModeの一部であり、ファイルタイプを示すビットマスクです。os.FileModeの値とos.ModeTypeをビットAND演算 (&) することで、ファイルのタイプ部分のみを抽出できます。例えば、fi.Mode() & os.ModeTypeは、ファイルのタイプ(ディレクトリ、シンボリックリンクなど)を示すビットのみを保持します。 -
os.FileMode.Perm()メソッド:Perm()メソッドは、os.FileModeの値からパーミッションビットのみを抽出し、os.FileMode型として返します。ファイルタイプに関するビットはマスクされます。 -
os.FileMode.IsRegular()メソッド:IsRegular()メソッドは、os.FileModeの値が通常のファイル(ディレクトリ、シンボリックリンクなどではない)を表している場合にtrueを返します。これは、fi.Mode() & os.ModeType == 0と同等のチェックを、よりセマンティックな方法で提供します。
技術的詳細
このコミットの技術的な詳細は、Go言語におけるファイルモードの扱いと、よりイディオム的なコードへの移行にあります。
変更前のコードでは、fi.Mode()&os.ModeType == 0 という条件式を使用していました。
fi.Mode():os.FileInfoからファイルのモード(パーミッションとタイプ)を取得します。os.ModeType: ファイルタイプを示すビットマスクです。&: ビットAND演算子です。fi.Mode()とos.ModeTypeのビットANDを取ることで、fi.Mode()のうちファイルタイプに関するビットのみが抽出されます。== 0: 抽出されたファイルタイプビットがすべて0であるかをチェックします。os.ModeTypeで定義されるファイルタイプ(ディレクトリ、シンボリックリンク、デバイスなど)のいずれにも該当しない場合、この式はtrueになります。これは、ファイルが通常のファイルであることを意味します。
このアプローチは機能的には正しいですが、os.FileMode 型には IsRegular() という専用のメソッドが用意されています。このメソッドは、内部的に同様のチェックを行いますが、コードの意図をより明確に表現します。
変更後のコードでは、fi.Mode().IsRegular() という条件式を使用しています。
fi.Mode(): 同様にファイルのモードを取得します。.IsRegular():os.FileMode型のメソッドであり、レシーバ(この場合はfi.Mode()の結果)が通常のファイルを表す場合にtrueを返します。
この変更により、コードは以下の点で改善されます。
- 可読性の向上:
IsRegular()はその名前から直接的に「通常のファイルであるか」を判断していることが分かり、ビット演算子と定数の組み合わせよりも直感的です。 - イディオム的なGoコード: Go言語では、特定の目的のために用意されたメソッドや関数があれば、それらを使用することが推奨されます。これにより、コードがGoの慣習に沿ったものとなり、他のGo開発者にとって理解しやすくなります。
- 保守性の向上: 将来的に
os.FileModeの内部表現やos.ModeTypeの定義が変更された場合でも、IsRegular()メソッドはAPIとして安定しているため、このコードが影響を受ける可能性が低くなります。ビット演算子を直接使用する場合、これらの内部的な変更に追従する必要が生じる可能性があります。
このコミットは、Go言語の標準ライブラリが、単に機能するだけでなく、いかにクリーンでイディオム的なコードを追求しているかを示す良い例です。
コアとなるコードの変更箇所
変更は src/pkg/archive/tar/common.go ファイルの1箇所のみです。
--- a/src/pkg/archive/tar/common.go
+++ b/src/pkg/archive/tar/common.go
@@ -80,7 +80,7 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
Mode: int64(fi.Mode().Perm()), // or'd with c_IS* constants later
}\n \tswitch {\n-\tcase fi.Mode()&os.ModeType == 0:\n+\tcase fi.Mode().IsRegular():\n \t\th.Mode |= c_ISREG\n \t\th.Typeflag = TypeReg\n \t\th.Size = fi.Size()\
コアとなるコードの解説
この変更は、FileInfoHeader 関数内の switch ステートメントの最初の case 文にあります。
FileInfoHeader 関数は、os.FileInfo オブジェクトとリンクパスを受け取り、TARアーカイブのヘッダー (*Header) を生成する役割を担っています。この関数内で、ファイルのタイプに基づいて異なる処理を行うために switch ステートメントが使用されています。
変更前のコード:
case fi.Mode()&os.ModeType == 0:
この行は、「fi(os.FileInfo)のモードからファイルタイプに関するビットを抽出し、それが0である(つまり、通常のファイルタイプではない)場合」という条件をチェックしていました。結果として、これは通常のファイルであるかを判断していました。
変更後のコード:
case fi.Mode().IsRegular():
この行は、「fi(os.FileInfo)のモードが通常のファイルである場合」という条件をチェックしています。IsRegular() メソッドは、os.FileMode 型に定義されており、そのレシーバが通常のファイルを表す場合に true を返します。
この変更により、コードの意図がより明確になり、Go言語のイディオムに沿った記述になりました。機能的な振る舞いは変わらず、コードの可読性と保守性が向上しています。
関連リンク
- Go言語のコミットページ: https://github.com/golang/go/commit/e7fe1944acb96de2fce832c11a1577a9e8e7a80a
- Go CL (Code Review) 7305043: https://golang.org/cl/7305043
参考にした情報源リンク
- Go Documentation:
ospackage: https://pkg.go.dev/os - Go Documentation:
os.FileInfointerface: https://pkg.go.dev/os#FileInfo - Go Documentation:
os.FileModetype: https://pkg.go.dev/os#FileMode - Go Documentation:
os.FileMode.IsRegular()method: https://pkg.go.dev/os#FileMode.IsRegular - Go Documentation:
os.ModeTypeconstant: https://pkg.go.dev/os#ModeType