[インデックス 11817] ファイルの概要
このコミットは、Go言語の標準ライブラリであるstrings
パッケージのexample_test.go
ファイルに、より多くの使用例を追加するものです。これにより、strings
パッケージの各関数の使い方をより明確に示し、開発者がこれらの関数を理解し、適切に利用する手助けをすることを目的としています。
コミット
commit 71c8b82dd1e59f1864dd347ea76726406f871365
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Mon Feb 13 14:05:57 2012 +1100
strings: more examples
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5645092
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/71c8b82dd1e59f1864dd347ea76726406f871365
元コミット内容
strings: more examples
このコミットは、Go言語のstrings
パッケージに、より多くの使用例を追加します。
変更の背景
Go言語の標準ライブラリは、その使いやすさと豊富な機能で知られています。strings
パッケージは、文字列操作のための基本的な機能を提供し、Goプログラムの多くの部分で利用されます。しかし、ライブラリの機能が豊富であるほど、各関数の具体的な使用方法や、どのような結果が期待されるのかを理解するための明確な例が重要になります。
このコミットが行われた2012年2月時点では、Go言語はまだ比較的新しい言語であり、ドキュメンテーションや使用例の充実は、言語の普及と開発者の学習体験向上に不可欠でした。特に、strings
パッケージのような頻繁に使用されるパッケージでは、直感的で分かりやすい例を提供することで、開発者がコードをより迅速に書き、一般的な文字列操作タスクを効率的に解決できるようになります。
このコミットの目的は、strings
パッケージの既存の関数に対して、より多くのExample
関数を追加することです。Goのテストフレームワークでは、Example
関数はドキュメンテーションの一部として扱われ、go doc
コマンドで表示されるだけでなく、自動的にテストとして実行され、出力が期待通りであるか検証されます。これにより、ドキュメンテーションの正確性が保証され、常に最新の動作を反映するようになります。
したがって、この変更は、strings
パッケージのドキュメンテーションを強化し、開発者がGo言語で文字列操作を行う際の生産性を向上させることを目的としています。
前提知識の解説
Go言語のstrings
パッケージ
Go言語のstrings
パッケージは、UTF-8でエンコードされた文字列を操作するための基本的な関数を提供します。これには、文字列の検索、置換、分割、結合、大文字・小文字変換、トリミングなど、多岐にわたる機能が含まれます。strings
パッケージの関数は、Goの標準ライブラリの一部として、Goプログラムで文字列を扱う際の基盤となります。
Go言語のExample
関数
Go言語のテストパッケージ(testing
)には、Example
関数という特別な種類の関数があります。これは、通常のテスト関数(TestXxx
)やベンチマーク関数(BenchmarkXxx
)とは異なり、コードの動作例を示すために使用されます。
Example
関数の特徴は以下の通りです。
- ドキュメンテーションとしての機能:
Example
関数は、go doc
コマンドを実行した際に、対応する関数やパッケージのドキュメンテーションの一部として表示されます。これにより、開発者は関数の使い方をコード例で直接確認できます。 - 自動テストとしての機能:
Example
関数は、go test
コマンドを実行した際に、通常のテストと同様に実行されます。Example
関数のコメント行にOutput:
というプレフィックスで期待される出力が記述されている場合、GoのテストランナーはそのExample
関数を実行し、標準出力に書き込まれた内容がOutput:
に続く内容と一致するかどうかを検証します。これにより、ドキュメンテーションのコード例が常に正しく動作することが保証されます。 - 命名規則:
Example
関数は、Example
、ExampleF
、ExampleT
、ExampleP
、Example_suffix
、ExampleF_suffix
、ExampleT_suffix
、ExampleP_suffix
といった命名規則に従います。ここでF
は関数名、T
は型名、P
はパッケージ名を表します。例えば、strings.Contains
関数の例であればExampleContains
という名前になります。
このコミットは、このExample
関数の仕組みを利用して、strings
パッケージの各関数の使用例を豊富に追加しています。
技術的詳細
このコミットは、src/pkg/strings/example_test.go
ファイルに、strings
パッケージの様々な関数に対するExample
関数を追加しています。追加されたExample
関数は、それぞれの関数の典型的な使用方法と、その実行結果をfmt.Println
やfmt.Printf
で出力し、その出力がOutput:
コメントで期待される結果と一致するかをgo test
時に検証します。
具体的に追加されたExample
関数は以下の通りです。
ExampleContains()
:strings.Contains
関数の使用例。文字列が特定のサブストリングを含むかどうかをチェックします。ExampleContainsAny()
:strings.ContainsAny
関数の使用例。文字列が指定された文字セットのいずれかの文字を含むかどうかをチェックします。ExampleCount()
:strings.Count
関数の使用例。文字列内で特定のサブストリングが何回出現するかを数えます。ExampleEqualFold()
:strings.EqualFold
関数の使用例。UTF-8文字列を大文字・小文字を区別せずに比較します。ExampleIndex()
:strings.Index
関数の使用例。文字列内でサブストリングが最初に出現するインデックスを返します。ExampleRune()
:strings.IndexRune
関数の使用例。文字列内で特定のルーン(Unicodeコードポイント)が最初に出現するインデックスを返します。ExampleLastIndex()
:strings.LastIndex
関数の使用例。文字列内でサブストリングが最後に出現するインデックスを返します。ExampleJoin()
:strings.Join
関数の使用例。文字列スライスを区切り文字で結合します。ExampleRepeat()
:strings.Repeat
関数の使用例。文字列を指定された回数繰り返します。ExampleReplace()
:strings.Replace
関数の使用例。文字列内のサブストリングを別のサブストリングで置換します。ExampleSplit()
:strings.Split
関数の使用例。文字列を区切り文字で分割します。ExampleSplitN()
:strings.SplitN
関数の使用例。文字列を区切り文字で最大N回分割します。ExampleSplitAfter()
:strings.SplitAfter
関数の使用例。文字列を区切り文字の後に分割します。ExampleSplitAfterN()
:strings.SplitAfterN
関数の使用例。文字列を区切り文字の後に最大N回分割します。ExampleTitle()
:strings.Title
関数の使用例。文字列をタイトルケースに変換します。ExampleToTitle()
:strings.ToTitle
関数の使用例。文字列をUnicodeのタイトルケースに変換します。ExampleTrim()
:strings.Trim
関数の使用例。文字列の先頭と末尾から指定された文字セットの文字を削除します。ExampleMap()
:strings.Map
関数の使用例。文字列の各ルーンに関数を適用して新しい文字列を生成します。例としてROT13エンコーディングが示されています。ExampleTrimSpace()
:strings.TrimSpace
関数の使用例。文字列の先頭と末尾から空白文字を削除します。ExampleNewReplacer()
:strings.NewReplacer
関数の使用例。複数の置換ペアを効率的に処理するためのReplacer
オブジェクトを作成します。ExampleToUpper()
:strings.ToUpper
関数の使用例。文字列を大文字に変換します。ExampleToLower()
:strings.ToLower
関数の使用例。文字列を小文字に変換します。
これらの例は、各関数の基本的な使い方だけでなく、エッジケース(例: 空文字列の扱い)や、特定の引数(例: strings.Replace
のn
引数、strings.SplitN
のn
引数)が結果にどのように影響するかを示しています。
コアとなるコードの変更箇所
変更はすべてsrc/pkg/strings/example_test.go
ファイルに対して行われています。
--- a/src/pkg/strings/example_test.go
+++ b/src/pkg/strings/example_test.go
@@ -13,3 +13,158 @@ import (
func ExampleFields() {
fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz "))
}
+
+// true
+// false
+// true
+// true
+func ExampleContains() {
+ fmt.Println(strings.Contains("seafood", "foo"))
+ fmt.Println(strings.Contains("seafood", "bar"))
+ fmt.Println(strings.Contains("seafood", ""))
+ fmt.Println(strings.Contains("", ""))
+}
+
+// false
+// true
+// false
+// false
+func ExampleContainsAny() {
+ fmt.Println(strings.ContainsAny("team", "i"))
+ fmt.Println(strings.ContainsAny("failure", "u & i"))
+ fmt.Println(strings.ContainsAny("foo", ""))
+ fmt.Println(strings.ContainsAny("", ""))
+
+}
+
+// 3
+// 5
+func ExampleCount() {
+ fmt.Println(strings.Count("cheese", "e"))
+ fmt.Println(strings.Count("five", "")) // before & after each rune
+}
+
+// true
+func ExampleEqualFold() {
+ fmt.Println(strings.EqualFold("Go", "go"))
+}
+
+// 4
+// -1
+func ExampleIndex() {
+ fmt.Println(strings.Index("chicken", "ken"))
+ fmt.Println(strings.Index("chicken", "dmr"))
+}
+
+// 4
+// -1
+func ExampleRune() {
+ fmt.Println(strings.IndexRune("chicken", 'k'))
+ fmt.Println(strings.IndexRune("chicken", 'd'))
+}
+
+// 0
+// 3
+// -1
+func ExampleLastIndex() {
+ fmt.Println(strings.Index("go gopher", "go"))
+ fmt.Println(strings.LastIndex("go gopher", "go"))
+ fmt.Println(strings.LastIndex("go gopher", "rodent"))
+}
+
+// foo, bar, baz
+func ExampleJoin() {
+ s := []string{"foo", "bar", "baz"}
+ fmt.Println(strings.Join(s, ", "))
+}
+
+// banana
+func ExampleRepeat() {
+ fmt.Println("ba" + strings.Repeat("na", 2))
+}
+
+// oinky oinky oink
+// moo moo moo
+func ExampleReplace() {
+ fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
+ fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1))
+}
+
+// ["a" "b" "c"]
+// ["" "man " "plan " "canal panama"]
+// [" " "x" "y" "z" " "]
+func ExampleSplit() {
+ fmt.Printf("%q\n", strings.Split("a,b,c", ","))
+ fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
+ fmt.Printf("%q\n", strings.Split(" xyz ", ""))
+}
+
+// ["a" "b,c"]
+// [] (nil = true)
+func ExampleSplitN() {
+ fmt.Printf("%q\n", strings.SplitN("a,b,c", ",", 2))
+ z := strings.SplitN("a,b,c", ",", 0)
+ fmt.Printf("%q (nil = %v)\n", z, z == nil)
+}
+
+// ["a," "b," "c"]
+func ExampleSplitAfter() {
+ fmt.Printf("%q\n", strings.SplitAfter("a,b,c", ","))
+}
+
+// ["a," "b,c"]
+func ExampleSplitAfterN() {
+ fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", 2))
+}
+
+// Her Royal Highness
+func ExampleTitle() {
+ fmt.Println(strings.Title("her royal highness"))
+}
+
+// LOUD NOISES
+// ХЛЕБ
+func ExampleToTitle() {
+ fmt.Println(strings.ToTitle("loud noises"))
+ fmt.Println(strings.ToTitle("хлеб"))
+}
+
+// [Achtung]
+func ExampleTrim() {
+ fmt.Printf("[%s]", strings.Trim(" !!! Achtung !!! ", "! "))
+}
+
+// 'Gjnf oevyyvt naq gur fyvgul tbcure...
+func ExampleMap() {
+ rot13 := func(r rune) rune {
+ switch {
+ case r >= 'A' && r <= 'Z':
+ return 'A' + (r-'A'+13)%26
+ case r >= 'a' && r <= 'z':
+ return 'a' + (r-'a'+13)%26
+ }
+ return r
+ }
+ fmt.Println(strings.Map(rot13, "'Twas brillig and the slithy gopher..."))
+}
+
+// a lone gopher
+func ExampleTrimSpace() {
+ fmt.Println(strings.TrimSpace(" \t\n a lone gopher \n\t\r\n"))
+}
+
+// This is <b>HTML</b>!
+func ExampleNewReplacer() {
+ r := strings.NewReplacer("<", "<", ">", ">")
+ fmt.Println(r.Replace("This is <b>HTML</b>!"))
+}
+
+// GOPHER
+func ExampleToUpper() {
+ fmt.Println(strings.ToUpper("Gopher"))
+}
+
+// gopher
+func ExampleToLower() {
+ fmt.Println(strings.ToLower("Gopher"))
+}
コアとなるコードの解説
このコミットは、src/pkg/strings/example_test.go
ファイルに、strings
パッケージの様々な関数に対するExample
関数を大量に追加しています。
各Example
関数は、以下の構造に従っています。
- 関数定義:
func ExampleFunctionName() { ... }
の形式で定義されます。 - 関数呼び出しと出力:
strings
パッケージの対象関数を呼び出し、その結果をfmt.Println
やfmt.Printf
で標準出力に出力します。 - 期待される出力:
// Output:
で始まるコメント行の後に、上記の関数呼び出しによって標準出力に出力されると期待される内容が記述されています。go test
コマンドが実行されると、このコメントと実際の出力が比較され、一致しない場合はテストが失敗します。
例えば、ExampleContains()
関数では、strings.Contains
関数の様々なケース(部分文字列が見つかる場合、見つからない場合、空文字列を検索する場合など)が示され、それぞれの結果がtrue
またはfalse
として出力されることが期待されています。
特筆すべきは、ExampleMap()
関数で、strings.Map
関数の使用例としてROT13エンコーディングのロジックが示されています。これは、strings.Map
がルーン単位で文字列を変換する強力な機能を持つことを具体的に示しています。
また、ExampleSplit()
やExampleSplitN()
、ExampleSplitAfter()
、ExampleSplitAfterN()
のように、文字列の分割に関する複数の関数に対して、それぞれの挙動の違いが明確に分かるような例が提供されています。
これらの追加されたExample
関数は、strings
パッケージのドキュメンテーションを大幅に充実させ、開発者が各関数の機能と使い方を迅速に理解するための貴重なリソースとなります。
関連リンク
- Go言語の
strings
パッケージのドキュメンテーション: https://pkg.go.dev/strings (現在のバージョン) - Go言語の
testing
パッケージのドキュメンテーション: https://pkg.go.dev/testing (現在のバージョン)
参考にした情報源リンク
- Go言語の公式ドキュメンテーション
- Go言語の
testing
パッケージにおけるExample
関数の概念に関する一般的な情報源 - コミットメッセージと差分情報