[インデックス 11919] ファイルの概要
このコミットは、Go言語の標準ライブラリstrings
パッケージ内のexample_test.go
ファイルに、strings.Split
関数の新しい使用例を追加するものです。具体的には、空の文字列を特定のセパレータで分割した場合の挙動を示すテストケースが追加されています。
コミット
commit d6a3650ad71d8b071cf038ff8fe1c724b1ab74d0
Author: Andrew Gerrand <adg@golang.org>
Date: Wed Feb 15 13:38:28 2012 +1100
strings: add Bernardo O'Higgins example
R=r, bradfitz
CC=golang-dev, rogpeppe
https://golang.org/cl/5673049
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d6a3650ad71d8b071cf038ff8fe1c724b1ab74d0
元コミット内容
strings: add Bernardo O'Higgins example
R=r, bradfitz
CC=golang-dev, rogpeppe
https://golang.org/cl/5673049
変更の背景
このコミットの背景には、Go言語のstrings.Split
関数が、分割対象の文字列が空の場合にどのような結果を返すかという、特定のコーナーケースの挙動を明確にする意図があります。既存のExampleSplit
関数には、様々なstrings.Split
の利用例が含まれていましたが、空の文字列を非空のセパレータで分割するケースが欠けていました。
strings.Split
のような基本的な文字列操作関数は、その挙動が直感的でない場合に開発者を混乱させる可能性があります。特に、入力が空文字列の場合の挙動は、プログラミング言語によって異なることが多く、明示的な例を示すことで、ユーザーが予期せぬ結果に遭遇するのを防ぎ、コードの堅牢性を高めることができます。
「Bernardo O'Higgins」というセパレータが選ばれたのは、おそらくその長さとユニークさから、空文字列を分割する際にセパレータ自体が結果に影響を与えないことを強調するためと考えられます。これは、セパレータが空文字列でない限り、結果として単一の空文字列のスライスが返されるというstrings.Split
の特定の挙動を示すための、意図的な選択です。
前提知識の解説
Go言語のstrings.Split
関数
Go言語のstrings
パッケージは、UTF-8でエンコードされた文字列を操作するための多くのユーティリティ関数を提供します。その中でもstrings.Split
関数は、指定されたセパレータ文字列に基づいて、文字列を部分文字列のスライスに分割するために使用されます。
関数のシグネチャは以下の通りです。
func Split(s, sep string) []string
s
: 分割対象の文字列。sep
: セパレータとして使用する文字列。
strings.Split
の挙動は、s
とsep
が空文字列であるかどうかによっていくつかのパターンがあります。
-
s
が空文字列 (""
) で、sep
が空文字列ではない場合:strings.Split
は、単一の空文字列を含むスライス[]string{""}
を返します。 例:strings.Split("", ",")
は[]string{""}
を返します。 -
s
とsep
の両方が空文字列 (""
) の場合:strings.Split
は、空のスライス[]string{}
を返します。 例:strings.Split("", "")
は[]string{}
を返します。 -
sep
が空文字列 (""
) で、s
が空文字列ではない場合:strings.Split
は、s
の各UTF-8文字を個別の要素とするスライスを返します。 例:strings.Split("abc", "")
は[]string{"a", "b", "c"}
を返します。
このコミットで追加された例は、上記の1番目のケース、つまり「s
が空文字列で、sep
が空文字列ではない場合」の挙動を具体的に示しています。
Go言語のExample
関数とテスト
Go言語では、_test.go
ファイル内にExample
というプレフィックスを持つ関数を記述することで、コードの利用例をドキュメントとして提供し、同時にテストとして実行することができます。これらのExample
関数は、go test
コマンドを実行した際に、その出力がコメントに書かれた期待される出力と一致するかどうかを検証します。これにより、ドキュメントとコードの整合性が保たれ、コードの挙動が変更された場合にドキュメントも更新されることが保証されます。
Example
関数は通常、fmt.Print
やfmt.Printf
を使用して出力を生成し、その出力がOutput:
コメントブロックに記述された内容と一致するかどうかをテストします。
技術的詳細
このコミットは、src/pkg/strings/example_test.go
ファイルに新しいfmt.Printf
ステートメントを追加することで、strings.Split
関数の特定の挙動を例示しています。追加された行は以下の通りです。
fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
このコードは、空の文字列 ""
を、比較的長くユニークな文字列 "Bernardo O'Higgins"
をセパレータとしてstrings.Split
関数に渡しています。Go言語のstrings.Split
の仕様により、分割対象の文字列が空で、セパレータが空でない場合、結果は単一の空文字列を含むスライス []string{""}
となります。
fmt.Printf("%q\n", ...)
は、Goのフォーマット動詞 %q
を使用しています。%q
は、文字列やスライスをGoの構文でクォート(引用符で囲む)して出力します。これにより、スライスが [""]
のように表示され、単一の空文字列が要素として含まれていることが明確に示されます。
この例を追加することで、strings.Split
のドキュメントとテストカバレッジが向上し、特に空文字列の入力に対する関数の挙動に関する潜在的な混乱が解消されます。これは、ライブラリの堅牢性と使いやすさを向上させるための、小さなしかし重要な改善です。
コアとなるコードの変更箇所
--- a/src/pkg/strings/example_test.go
+++ b/src/pkg/strings/example_test.go
@@ -93,10 +93,12 @@ func ExampleReplace() {
// ["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 ", ""))
+\tfmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
}
// ["a" "b,c"]
コアとなるコードの解説
変更はsrc/pkg/strings/example_test.go
ファイルのExampleSplit
関数内で行われています。
追加された行は以下の通りです。
+\tfmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
この行は、strings.Split
関数に空の文字列 ""
と、セパレータとして "Bernardo O'Higgins"
を渡しています。この呼び出しの結果は、Goのstrings.Split
の仕様に従い、単一の空文字列を含むスライス []string{""}
となります。
fmt.Printf("%q\n", ...)
は、このスライスをGoの構文でクォートして出力します。したがって、この行の実行結果は [""]
となります。
この変更は、ExampleSplit
関数の既存の出力コメントに // [""]
という行を追加することと対になっています。これにより、go test
コマンドが実行された際に、この新しい例の出力が期待される出力と一致するかどうかが検証されます。
この追加により、strings.Split
が空の入力文字列に対してどのように振る舞うかという、重要なコーナーケースが明確に示され、ライブラリのドキュメントとテストカバレッジが強化されました。
関連リンク
- Go CL 5673049: https://golang.org/cl/5673049
参考にした情報源リンク
- Go strings.Split empty string behavior: