[インデックス 16352] ファイルの概要
このコミットは、Go言語の公式仕様書である doc/go_spec.html
ファイルに対する変更です。具体的には、range
キーワードの動作に関する記述を修正し、より正確な表現に更新しています。
コミット
- コミットハッシュ:
bb3a32ef6e6772ca6fefda119d0238aec6f7e585
- 作者: Robert Griesemer gri@golang.org
- 日付: Mon May 20 13:27:53 2013 -0700
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/bb3a32ef6e6772ca6fefda119d0238aec6f7e585
元コミット内容
spec: fix language about "range" clause
Fixes #5434.
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/9595044
変更の背景
このコミットの背景には、Go言語の range
キーワードの動作に関する仕様記述の曖昧さがありました。特に、配列、ポインタ、またはスライスに対して range
ループを使用し、かつ最初のイテレーション変数(通常はインデックス)のみを受け取る場合の挙動について、既存の記述が誤解を招く可能性がありました。
Go言語の range
ループは、コレクション(配列、スライス、文字列、マップ、チャネル)を反復処理するための強力な構文です。通常、for ... range ...
の形式で記述され、各イテレーションでキーと値(またはインデックスと値)のペアを返します。しかし、イテレーション変数を1つだけ指定した場合の動作は、コレクションの種類によって異なります。
このコミットでは、配列、ポインタ、スライスに対して range
を使用し、かつインデックスのみを受け取る場合に、イテレーション値が len(a)
ではなく len(a)-1
まで生成されることを明確にする必要がありました。これは、Go言語におけるインデックスが0から始まること、および len(a)
が要素の「数」を示すため、最後の有効なインデックスは len(a)-1
であるという基本的な原則に合致させるための修正です。
この修正は、Go言語の仕様の正確性を保ち、開発者が range
ループの挙動を正しく理解できるようにするために重要でした。
前提知識の解説
Go言語の仕様書 (The Go Programming Language Specification)
Go言語の仕様書は、Go言語の構文、セマンティクス、および標準ライブラリの動作を定義する公式文書です。Go言語の設計者によって維持されており、言語のあらゆる側面に関する究極の権威となります。開発者は、言語の特定の挙動について疑問が生じた場合、この仕様書を参照します。このコミットで変更された doc/go_spec.html
は、この仕様書のHTML版の一部です。
range
キーワード
Go言語の range
キーワードは、for
ループと組み合わせて使用され、配列、スライス、文字列、マップ、チャネルなどのコレクションを反復処理するために使われます。
基本的な構文は以下の通りです。
for index, value := range collection {
// index と value を使用した処理
}
または、インデックスのみ、あるいは値のみが必要な場合は、アンダースコア _
を使用して不要な変数を破棄できます。
for index := range collection {
// index を使用した処理
}
for _, value := range collection {
// value を使用した処理
}
range
の挙動はコレクションの種類によって異なります。
- 配列、スライス、文字列:
index
は要素のインデックス、value
はそのインデックスにある要素のコピーです。 - マップ:
index
はキー、value
はそのキーに対応する値です。マップの反復順序は保証されません。 - チャネル:
value
はチャネルから受信した値です。チャネルが閉じられるまで値を受信し続けます。
このコミットで特に焦点を当てているのは、配列、ポインタ、スライスに対して for index := range collection
の形式で range
を使用した場合の挙動です。
len()
関数
len()
はGo言語の組み込み関数で、配列、スライス、マップ、文字列、チャネルの長さを返します。
- 配列、スライス、文字列の場合、要素の数を返します。
- マップの場合、キーと値のペアの数を返します。
- チャネルの場合、チャネル内のキューに入れられた(まだ受信されていない)要素の数を返します。
Go言語では、配列やスライスのインデックスは0から始まります。したがって、len(a)
が配列 a
の要素の総数である場合、有効なインデックスは 0
から len(a)-1
までとなります。
技術的詳細
このコミットの技術的な核心は、Go言語の仕様書における range
ループの記述の微細ながらも重要な修正にあります。
変更前の仕様書では、配列、ポインタ、またはスライス a
に対して range
ループを使用し、かつ最初のイテレーション変数(インデックス)のみが指定された場合、イテレーション値が「0
から len(a)
まで」生成されると記述されていました。
しかし、Go言語のインデックスは0から始まるため、len(a)
は要素の総数を示し、最後の有効なインデックスは len(a)-1
です。もしイテレーション値が len(a)
まで生成されると解釈されると、それは配列やスライスの範囲外アクセス(out-of-bounds access)を示唆することになり、Go言語の基本的なインデックス付けの原則と矛盾します。
このコミットでは、この記述を「0
から len(a)-1
まで」に修正することで、仕様の正確性を確保しています。これにより、for index := range a
の形式でループを回した場合、index
は 0, 1, ..., len(a)-1
の値を取ることが明確になります。この修正は、range
ループが実際に配列やスライス自体をインデックス付けしない(つまり、a[index]
のようなアクセスを行わない)という事実と整合しています。単にインデックス値のみを生成するということです。
この変更は、Go言語の range
ループのセマンティクスをより厳密に定義し、開発者が誤解なくコードを記述できるようにするために不可欠でした。特に、range
ループの内部実装や最適化を理解する上で、この正確な記述は重要です。
コアとなるコードの変更箇所
変更は doc/go_spec.html
ファイルの以下の部分です。
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
- "Subtitle": "Version of May 14, 2013",
+ "Subtitle": "Version of May 20, 2013",
"Path": "/ref/spec"
}-->
@@ -4620,7 +4620,7 @@ channel c chan E, <-chan E element e E
For an array, pointer to array, or slice value <code>a</code>, the index iteration
values are produced in increasing order, starting at element index 0.
If only the first iteration variable is present, the range loop produces
-iteration values from 0 up to <code>len(a)</code> and does not index into the array
+iteration values from 0 up to <code>len(a)-1</code> and does not index into the array
or slice itself. For a <code>nil</code> slice, the number of iterations is 0.
</li>
具体的には、以下の2箇所が変更されています。
-
仕様書のバージョン日付の更新:
- "Subtitle": "Version of May 14, 2013",
+ "Subtitle": "Version of May 20, 2013",
これは、仕様書が更新された日付を反映するための単純な変更です。 -
range
ループの記述の修正:-iteration values from 0 up to <code>len(a)</code> and does not index into the array
+iteration values from 0 up to <code>len(a)-1</code> and does not index into the array
これがこのコミットの主要な変更点であり、range
ループがインデックスのみを生成する場合の挙動に関する記述を修正しています。
コアとなるコードの解説
このコミットの核心は、doc/go_spec.html
内の range
ループに関する説明文の変更です。
変更前の記述:
iteration values from 0 up to <code>len(a)</code> and does not index into the array
(イテレーション値は0から len(a)
まで生成され、配列をインデックス付けしない)
変更後の記述:
iteration values from 0 up to <code>len(a)-1</code> and does not index into the array
(イテレーション値は0から len(a)-1
まで生成され、配列をインデックス付けしない)
この修正は、Go言語の配列やスライスのインデックスが0から始まるという事実に基づいています。len(a)
は配列やスライスの要素の総数を返しますが、有効なインデックスは 0
から len(a)-1
までです。したがって、for index := range a
のようにインデックスのみを反復する場合、生成されるインデックス値は 0, 1, ..., len(a)-1
となります。
「len(a)
まで」という表現は、len(a)
自体も含まれるかのような誤解を招く可能性がありました。しかし、実際には len(a)
は有効なインデックスではありません。この修正により、range
ループがインデックスのみを生成する際の挙動が、Go言語のインデックス付けの慣習と完全に一致するように明確化されました。
また、「and does not index into the array or slice itself.」という部分は、for index := range a
の形式では、range
ループが実際に a[index]
のような操作を行って要素にアクセスするわけではなく、単にインデックス値のみを生成していることを強調しています。これは、例えば nil
スライスの場合でも、イテレーション回数が0になるという記述と整合しています。
この変更は、Go言語の仕様の正確性を高め、開発者が range
ループの挙動をより正確に理解し、それに基づいて堅牢なコードを記述できるようにするために重要です。
関連リンク
- The Go Programming Language Specification - Go言語の公式仕様書
- Effective Go - For loops -
range
ループを含むfor
ループに関するGoの慣用的な使い方
参考にした情報源リンク
- コミット情報:
/home/orange/Project/comemo/commit_data/16352.txt
- GitHubコミットページ: https://github.com/golang/go/commit/bb3a32ef6e6772ca6fefda119d0238aec6f7e585
- Go言語の公式ドキュメント (Go言語の
range
キーワードとlen()
関数に関する一般的な知識)