[インデックス 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