[インデックス 11986] ファイルの概要
このコミットは、Go言語の標準ライブラリであるpath/filepathパッケージのfilepath.Walk関数の使用例を、Go 1の公式ドキュメントに追加するものです。具体的には、filepath.Walkの動作を説明するHTMLドキュメント(doc/go1.htmlとdoc/go1.tmpl)に、新しいGoプログラムの例(doc/progs/go1.go)を埋め込むことで、ユーザーがfilepath.Walkの挙動、特にディレクトリのスキップ(filepath.SkipDir)の方法を視覚的に理解できるように改善しています。
コミット
- コミットハッシュ:
91672686da0af0d2e21b022c36b9977a78ec490f - 作者: Mike Rosset mike.rosset@gmail.com
- 日付: 2012年2月17日金曜日 12:45:55 +1100
- コミットメッセージ:
doc: provide example filepath.Walk for go1 R=golang-dev, r, r CC=golang-dev https://golang.org/cl/5674067
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/91672686da0af0d2e21b022c36b9977a78ec490f
元コミット内容
doc: provide example filepath.Walk for go1
R=golang-dev, r, r
CC=golang-dev
https://golang.org/cl/5674067
変更の背景
Go言語の初期バージョンであるGo 1のリリースに向けて、ドキュメントの充実が図られていました。path/filepathパッケージのWalk関数は、ファイルシステムを再帰的に走査するための非常に強力なツールですが、その使用方法、特に特定のディレクトリをスキップするfilepath.SkipDirの挙動は、初心者には直感的ではない場合があります。
このコミットの背景には、filepath.Walkのドキュメントに具体的なコード例が不足しており、ユーザーがこの関数を効果的に利用するための理解を深める必要があったという課題があります。既存のドキュメントには「TODO: add an example?」というコメントがあり、例の追加が求められていたことが示されています。この変更は、その要望に応え、Go 1のドキュメントの品質とユーザーフレンドリーさを向上させることを目的としています。
前提知識の解説
このコミットを理解するためには、以下のGo言語の概念と標準ライブラリに関する知識が必要です。
-
path/filepathパッケージ:- Go言語でファイルパスを操作するためのユーティリティを提供するパッケージです。プラットフォーム固有のパス区切り文字(Windowsの
\、Unix系の/)を抽象化し、クロスプラットフォームなパス操作を可能にします。 filepath.Walk(root string, walkFn WalkFunc) error: 指定されたrootパスから開始して、ファイルツリーを再帰的に走査する関数です。walkFnというコールバック関数を、走査中に見つかった各ファイルやディレクトリに対して呼び出します。WalkFunc型:filepath.Walkに渡されるコールバック関数の型定義です。type WalkFunc func(path string, info os.FileInfo, err error) errorpath: 現在走査しているファイルまたはディレクトリのパス。info: そのファイルまたはディレクトリのos.FileInfoインターフェース。ファイル名、サイズ、パーミッション、変更時刻などの情報を提供します。err:filepath.Walkがpathにアクセスしようとした際に発生したエラー。エラーがない場合はnil。WalkFuncがnil以外のエラーを返すと、filepath.Walkはそのエラーを返して走査を停止します。
filepath.SkipDir:WalkFuncがこの特殊なエラー値を返すと、filepath.Walkは現在のディレクトリの内容をスキップし、そのディレクトリの兄弟要素の走査を続行します。これは、特定のサブディレクトリを処理対象から除外したい場合に非常に便利です。
- Go言語でファイルパスを操作するためのユーティリティを提供するパッケージです。プラットフォーム固有のパス区切り文字(Windowsの
-
osパッケージ:- オペレーティングシステム機能へのアクセスを提供するパッケージです。
os.FileInfoインターフェース: ファイルやディレクトリのメタデータ(名前、サイズ、モード、変更時刻など)を抽象的に表現するためのインターフェースです。filepath.WalkのWalkFuncに渡されるinfo引数として使用されます。
-
logパッケージ:- ログメッセージを出力するためのシンプルなパッケージです。
log.Println(v ...interface{}): 引数をデフォルトのフォーマットで標準エラー出力に書き込み、改行を追加します。log.Fatal(v ...interface{}):Printlnと同様にログを出力した後、os.Exit(1)を呼び出してプログラムを終了します。
-
Goのドキュメント生成:
- Goのドキュメントは、Goのソースコード内のコメントや、専用のMarkdown/HTMLファイルから生成されます。このコミットでは、
doc/go1.htmlとdoc/go1.tmplがGo 1のドキュメントの一部であり、doc/progs/go1.goはドキュメントに埋め込まれるコード例を格納するファイルです。 {{code "progs/go1.go" /STARTWALK/ /ENDWALK/}}のような構文は、Goのドキュメントツールがprogs/go1.goファイルから/STARTWALK/と/ENDWALK/マーカーで囲まれたコードブロックを抽出し、それをHTMLドキュメントに埋め込むためのディレクティブです。これにより、ドキュメント内のコード例と実際の実行可能なコードが同期され、常に最新の状態に保たれます。
- Goのドキュメントは、Goのソースコード内のコメントや、専用のMarkdown/HTMLファイルから生成されます。このコミットでは、
技術的詳細
このコミットは、Go 1のドキュメントにおけるfilepath.Walk関数の説明セクションに、具体的なコード例を組み込むことで、その理解を深めることを目的としています。
変更は主に以下の3つのファイルにわたります。
-
doc/go1.html:- このファイルは、Go 1のドキュメントのHTMLバージョンです。
- 以前は
filepath.Walkの説明の後に「TODO: add an example?」というコメントと、赤字で例の追加を促すプレースホルダーがありました。 - このコミットでは、そのプレースホルダーが削除され、代わりに
doc/progs/go1.goから抽出されたfilepath.Walkの具体的なGoコード例が<pre>タグ内に直接埋め込まれています。 - また、
SkipDirの参照が単なるコードスニペットから、/pkg/path/filepath/#variablesへのハイパーリンクを含むfilepath.SkipDirに変更され、より公式なドキュメントへの参照が提供されています。
-
doc/go1.tmpl:- このファイルは、Go 1のドキュメントのテンプレートファイルであり、HTMLドキュメントを生成するための元となるものです。
doc/go1.htmlと同様に、「TODO: add an example?」のコメントとプレースホルダーが削除されました。- 最も重要な変更は、
{{code "progs/go1.go" /STARTWALK/ /ENDWALK/}}というテンプレートディレクティブが追加されたことです。これは、Goのドキュメント生成システムに対し、doc/progs/go1.goファイル内のSTARTWALKとENDWALKというコメントマーカーで囲まれたコードブロックを抽出し、この位置に挿入するように指示します。これにより、ドキュメントのHTMLバージョンとテンプレートバージョンの両方で、動的にコード例が埋め込まれるようになります。 SkipDirの参照もfilepath.SkipDirに更新され、パッケージ内の変数へのリンクが追加されています。
-
doc/progs/go1.go:- このファイルは、Go 1のドキュメント内で使用される様々なコード例をまとめたGoプログラムです。
- 新しい
func walkExample()関数が追加されました。この関数はfilepath.Walkの具体的な使用例を含んでいます。 main関数内でwalkExample()が呼び出されるように変更され、この例が実行可能なプログラムの一部として統合されました。path/filepathパッケージがインポートリストに追加されました。// STARTWALK OMITと// ENDWALK OMITという特殊なコメントがwalkExample関数の前後に追加されています。これらは、doc/go1.tmplで使用されている{{code ...}}ディレクティブが、この特定のコードブロックを正確に抽出するために使用するマーカーです。OMITは、ドキュメント生成時にこれらのコメント行自体は出力しないことを示します。
これらの変更により、Go 1のドキュメントはfilepath.Walkの機能とfilepath.SkipDirの利用方法を、実際の動作するコード例を通じてより明確に説明できるようになりました。
コアとなるコードの変更箇所
このコミットのコアとなるコードの変更は、主にdoc/progs/go1.goファイルに新しいwalkExample関数が追加された点です。
--- a/doc/progs/go1.go
+++ b/doc/progs/go1.go
@@ -12,6 +12,7 @@ import (
"fmt"
"log"
"os"
+ "path/filepath"
"testing"
"time"
"unicode"
@@ -28,6 +29,7 @@ func main() {
runType()
errorExample()
timePackage()
+ walkExample()
osIsExist()
}
@@ -183,6 +185,25 @@ func timePackage() {
sleepUntil(time.Now().Add(123 * time.Millisecond))\n}\n
+func walkExample() {
+ // STARTWALK OMIT
+ markFn := func(path string, info os.FileInfo, err error) error {
+ if path == "pictures" { // Will skip walking of directory pictures and its contents.
+ return filepath.SkipDir
+ }
+ if err != nil {
+ return err
+ }
+ log.Println(path)
+ return nil
+ }
+ err := filepath.Walk(".", markFn)
+ if err != nil {
+ log.Fatal(err)
+ }
+ // ENDWALK OMIT
+}
+
func initializationFunction(c chan int) {
c <- 1
}
コアとなるコードの解説
追加されたwalkExample関数は、filepath.Walkの典型的な使用パターンを示しています。
func walkExample() {
// STARTWALK OMIT
markFn := func(path string, info os.FileInfo, err error) error {
if path == "pictures" { // Will skip walking of directory pictures and its contents.
return filepath.SkipDir
}
if err != nil {
return err
}
log.Println(path)
return nil
}
err := filepath.Walk(".", markFn)
if err != nil {
log.Fatal(err)
}
// ENDWALK OMIT
}
-
markFnの定義:filepath.Walkに渡すWalkFunc型の匿名関数markFnを定義しています。- この関数は、
path(現在のファイル/ディレクトリのパス)、info(ファイル情報)、err(エラー)の3つの引数を受け取ります。
-
ディレクトリのスキップ条件:
if path == "pictures" { return filepath.SkipDir }- これがこの例の最も重要な部分です。もし現在のパスが文字列
"pictures"と一致した場合(つまり、カレントディレクトリ直下のpicturesという名前のディレクトリに遭遇した場合)、markFnはfilepath.SkipDirを返します。 filepath.SkipDirが返されると、filepath.Walkはpicturesディレクトリとその中のすべての内容の走査をスキップし、picturesディレクトリの兄弟要素(同じ階層にある他のファイルやディレクトリ)の走査を続行します。これにより、特定のサブツリーを効率的に無視できます。
- これがこの例の最も重要な部分です。もし現在のパスが文字列
-
エラーハンドリング:
if err != nil { return err }filepath.Walkがpathにアクセスする際にエラーが発生した場合(例: 権限がない、ファイルが存在しないなど)、そのエラーをmarkFnに渡します。markFnがこのエラーをそのまま返すと、filepath.Walkは直ちに走査を中止し、そのエラーを呼び出し元に返します。これは、ファイルシステム走査中に致命的な問題が発生した場合の標準的なエラー処理パターンです。
-
パスの出力:
log.Println(path)- エラーがなく、かつディレクトリがスキップされない場合、現在のファイルまたはディレクトリのパスを標準出力にログとして出力します。これにより、
filepath.Walkが実際にどのパスを訪れたかを確認できます。
- エラーがなく、かつディレクトリがスキップされない場合、現在のファイルまたはディレクトリのパスを標準出力にログとして出力します。これにより、
-
正常終了:
return nilmarkFnがnilを返すと、filepath.Walkは走査を続行します。
-
filepath.Walkの呼び出し:err := filepath.Walk(".", markFn)- カレントディレクトリ(
.)からファイルシステム走査を開始し、定義したmarkFnをコールバックとして使用します。
- カレントディレクトリ(
-
メインのエラーハンドリング:
if err != nil { log.Fatal(err) }filepath.Walk関数自体がエラーを返した場合(例:markFnがエラーを返して走査が中止された場合)、そのエラーをlog.Fatalで出力し、プログラムを終了します。
この例は、filepath.Walkの基本的な使い方、WalkFuncの構造、そして特にfilepath.SkipDirを使って特定のサブディレクトリを効率的にスキップする方法を明確に示しています。
関連リンク
- Go CL (Change List) 5674067: https://golang.org/cl/5674067
参考にした情報源リンク
- 特になし。コミット内容とGo言語の標準ライブラリの知識に基づいて解説を生成しました。