[インデックス 15313] ファイルの概要
このコミットは、Go言語の標準ライブラリである path/filepath
パッケージに、SplitList
関数と Rel
関数の使用例を追加するものです。具体的には、Unix系システムでの動作を示す src/pkg/path/filepath/example_unix_test.go
という新しいテストファイルが追加されました。このファイルは、SplitList
がパスリスト文字列をどのように分割するか、そして Rel
が2つのパス間の相対パスをどのように計算するかを、具体的なコード例と期待される出力で示しています。
コミット
- コミットハッシュ:
04567299771d99206101e3273b1851518cad491a
- 作者: Kamil Kisiel kamil@kamilkisiel.net
- コミット日時: 2013年2月19日 火曜日 10:41:35 -0800
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/04567299771d99206101e3273b1851518cad491a
元コミット内容
path/filepath: add examples for SplitList and Rel.
R=golang-dev, bradfitz, minux.ma
CC=golang-dev
https://golang.org/cl/7291043
変更の背景
Go言語の標準ライブラリは、その堅牢性と使いやすさで知られていますが、各関数の具体的な使用方法や挙動を理解するためには、公式ドキュメントだけでなく、具体的なコード例が非常に役立ちます。特に path/filepath
パッケージのようなファイルパス操作に関連する関数は、オペレーティングシステムごとのパス区切り文字の違いや、相対パスの計算におけるエッジケースなど、直感的に理解しにくい側面を持つことがあります。
このコミットは、SplitList
と Rel
という2つの重要な関数について、その典型的な使用例と、特定の入力に対する期待される出力を示すことで、開発者がこれらの関数をより正確に、そして効率的に利用できるようにすることを目的としています。これにより、ドキュメントの補完と、ライブラリの利用促進が図られています。
前提知識の解説
Go言語の path/filepath
パッケージ
path/filepath
パッケージは、Go言語でファイルパスを操作するためのユーティリティ関数を提供します。このパッケージは、オペレーティングシステム(OS)に依存しないパス操作を可能にする path
パッケージとは異なり、実行中のOSのパス区切り文字(Unix系では /
、Windowsでは \
)やパスリスト区切り文字(Unix系では :
、Windowsでは ;
)を考慮して動作します。これにより、クロスプラットフォームなアプリケーション開発において、ファイルパスの正規化、結合、分割、相対パスの計算などを安全に行うことができます。
filepath.SplitList
関数
filepath.SplitList
関数は、OSのパスリスト区切り文字(PathListSeparator
)で区切られた文字列を、個々のパスのリストに分割します。例えば、Unix系システムでは環境変数 PATH
のような形式の文字列(例: /usr/local/bin:/usr/bin:/bin
)を、個々のディレクトリパスの配列に変換する際に使用されます。
filepath.Rel
関数
filepath.Rel
関数は、base
パスから target
パスへの相対パスを計算します。例えば、/home/user/documents
を base
とし、/home/user/documents/report.txt
を target
とした場合、Rel
は report.txt
を返します。この関数は、ファイルシステム上の位置関係を簡潔に表現するために非常に有用です。ただし、base
と target
が異なるドライブや異なるファイルシステム上にある場合など、相対パスを計算できない場合にはエラーを返します。
技術的詳細
filepath.SplitList
の挙動
filepath.SplitList
は、内部的にOS固有の PathListSeparator
を使用して文字列を分割します。Unix系システムでは PathListSeparator
はコロン(:
)であり、Windowsではセミコロン(;
)です。この関数は、空のパス要素も適切に処理し、結果のリストに含めます。例えば、a::b
のような入力は ["a", "", "b"]
と分割されます。
filepath.Rel
の挙動とエッジケース
filepath.Rel(base, target)
は、以下のロジックに基づいて相対パスを計算します。
- 共通のプレフィックスの特定:
base
とtarget
の両方から共通のプレフィックス(最も長い共通の親ディレクトリ)を特定します。 base
から共通プレフィックスへの移動:base
から共通プレフィックスに戻るために必要な..
(親ディレクトリ) の数を計算します。- 共通プレフィックスから
target
への移動: 共通プレフィックスからtarget
に到達するために必要なパスの残りの部分を結合します。
エッジケース:
base
とtarget
が同じ:Rel("/a/b", "/a/b")
は.
を返します。target
がbase
の子孫:Rel("/a", "/a/b/c")
はb/c
を返します。base
がtarget
の子孫:Rel("/a/b/c", "/a")
は../../
を返します。base
とtarget
が共通の親を持つが、一方が他方の祖先ではない:Rel("/a/b", "/a/c")
は../c
を返します。- 相対パスを計算できない場合:
- 異なるドライブレター(Windowsの場合):
Rel("C:/a", "D:/b")
はエラーを返します。 base
が絶対パスでtarget
が相対パス、またはその逆の場合:Rel("/a", "b/c")
のように、base
とtarget
の種類(絶対パスか相対パスか)が異なる場合、Rel
はエラーを返すことがあります。今回の例では、base
が絶対パス/a
で、target
が相対パス./b/c
の場合にエラーRel: can't make b/c relative to /a
が発生しています。これは、Rel
が同じルート(または同じ相対的な基準)を持つパス間でしか相対パスを計算できないためです。
- 異なるドライブレター(Windowsの場合):
example_unix_test.go
ファイルの役割
Go言語では、_test.go
で終わるファイルはテストファイルとして扱われます。Example
関数は、Goのドキュメンテーションツール godoc
によって自動的に抽出され、パッケージのドキュメントにコード例として表示されます。これにより、ユーザーは go doc
コマンドや pkg.go.dev などのオンラインドキュメントを通じて、関数の使用例を直接確認できます。
また、// Output:
コメントは、go test
コマンドでテストを実行する際に、例の出力がこのコメントと一致するかどうかを検証するために使用されます。これにより、コード例が常に最新の挙動を反映していることが保証されます。
// +build !windows,!plan9
というビルドタグは、このファイルがWindowsおよびPlan 9以外のOSでのみコンパイルされることを示しています。これは、path/filepath
パッケージの挙動がOSによって異なるため、Unix系システムに特化した例であることを明示するためです。
コアとなるコードの変更箇所
src/pkg/path/filepath/example_unix_test.go
という新しいファイルが追加されました。
--- /dev/null
+++ b/src/pkg/path/filepath/example_unix_test.go
@@ -0,0 +1,39 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows,!plan9
+
+package filepath_test
+
+import (
+ "fmt"
+ "path/filepath"
+)
+
+func ExampleSplitList() {
+ fmt.Println("On Unix:", filepath.SplitList("/a/b/c:/usr/bin"))
+ // Output:
+ // On Unix: [/a/b/c /usr/bin]
+}
+
+func ExampleRel() {
+ paths := []string{
+ "/a/b/c",
+ "/b/c",
+ "./b/c",
+ }
+ base := "/a"
+
+ fmt.Println("On Unix:")
+ for _, p := range paths {
+ rel, err := filepath.Rel(base, p)
+ fmt.Printf("%q: %q %v\n", p, rel, err)
+ }
+
+ // Output:
+ // On Unix:
+ // "/a/b/c": "b/c" <nil>
+ // "/b/c": "../b/c" <nil>
+ // "./b/c": "" Rel: can't make b/c relative to /a
+}
コアとなるコードの解説
ExampleSplitList
関数
この関数は filepath.SplitList
の基本的な使用法を示しています。
func ExampleSplitList() {
fmt.Println("On Unix:", filepath.SplitList("/a/b/c:/usr/bin"))
// Output:
// On Unix: [/a/b/c /usr/bin]
}
- 入力文字列
"/a/b/c:/usr/bin"
は、Unix系システムにおける典型的なパスリスト形式です。 filepath.SplitList
は、この文字列をコロン(:
)で分割し、[]string{"/a/b/c", "/usr/bin"}
という文字列スライスを返します。fmt.Println
で出力される結果は、// Output:
コメントに記載されている通りOn Unix: [/a/b/c /usr/bin]
となります。
ExampleRel
関数
この関数は filepath.Rel
の様々なシナリオでの使用法と、エラーハンドリングを示しています。
func ExampleRel() {
paths := []string{
"/a/b/c",
"/b/c",
"./b/c",
}
base := "/a"
fmt.Println("On Unix:")
for _, p := range paths {
rel, err := filepath.Rel(base, p)
fmt.Printf("%q: %q %v\n", p, rel, err)
}
// Output:
// On Unix:
// "/a/b/c": "b/c" <nil>
// "/b/c": "../b/c" <nil>
// "./b/c": "" Rel: can't make b/c relative to /a
}
-
base
パスは"/a"
に設定されています。 -
paths
スライスには、異なる種類のターゲットパスが含まれています。"/a/b/c"
:base
の子孫パスです。filepath.Rel("/a", "/a/b/c")
はb/c
を返します。エラーは発生しません(<nil>
)。
"/b/c"
:base
とは異なるルートを持つ絶対パスです。filepath.Rel("/a", "/b/c")
は../b/c
を返します。これは、/a
から親ディレクトリに戻り(..
)、そこから/b/c
へ進むことを意味します。エラーは発生しません(<nil>
)。
"./b/c"
: 相対パスです。filepath.Rel("/a", "./b/c")
はエラーを返します。出力は"" Rel: can't make b/c relative to /a
となります。これは、Rel
関数が絶対パスと相対パスの間で相対パスを計算できないためです。base
が絶対パスであるのに対し、target
が相対パスであるため、Rel
は有効な相対パスを生成できません。
この例は、Rel
関数がどのように動作するか、特に異なるパスタイプ(絶対パスと相対パス)が混在する場合のエラー挙動を明確に示しており、開発者がこれらの関数を安全に利用するための重要な情報を提供しています。
関連リンク
- Go言語
path/filepath
パッケージの公式ドキュメント: https://pkg.go.dev/path/filepath - Go言語の
Example
関数に関するドキュメント: https://go.dev/blog/examples