[インデックス 14929] ファイルの概要
このコミットは、Go言語の公式仕様書(doc/go_spec.html
)におけるrange
句とselect
ステートメントの左辺(LHS: Left-Hand Side)の構文定義を明確化するものです。具体的には、これらの構文における代入(=
)と短い変数宣言(:=
)の左辺が、単一の式ではなくExpressionList
またはIdentifierList
であることを明示するように修正されています。これにより、仕様の曖昧さが解消され、より正確な言語定義が提供されます。
コミット
commit d3679726b4639c27ca6b632374cdf4be1c74dbb6
Author: Robert Griesemer <gri@golang.org>
Date: Fri Jan 18 13:59:25 2013 -0800
spec: clarify lhs syntax for range and select
Fixes #4653.
R=rsc, r, iant, ken, thakis
CC=golang-dev
https://golang.org/cl/7135058
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d3679726b4639c27ca6b632374cdf4be1c74dbb6
元コミット内容
spec: clarify lhs syntax for range and select
Fixes #4653.
R=rsc, r, iant, ken, thakis
CC=golang-dev
https://golang.org/cl/7135058
変更の背景
この変更は、Go言語の仕様書におけるrange
句とselect
ステートメントの構文定義が、実際の言語の挙動と完全に一致していなかった、あるいは曖昧であった点を修正するために行われました。特に、Go言語ではrange
やselect
の受信操作(RecvStmt
)において、複数の変数への代入や短い変数宣言が可能です。しかし、以前の仕様書では、左辺が単一のExpression
であるかのように記述されており、これが誤解を招く可能性がありました。
この問題は、GoのIssue #4653「spec: range and select lhs syntax
」として報告されていました。このIssueでは、range
とselect
の左辺の構文が、Expression
ではなくExpressionList
またはIdentifierList
であるべきだと指摘されていました。このコミットは、その指摘を受けて仕様書を修正し、言語の正確な定義を保証することを目的としています。
前提知識の解説
Go言語の仕様書 (Go Language Specification)
Go言語の仕様書は、Go言語の構文、セマンティクス、および標準ライブラリの動作を正式に定義する文書です。Go言語の設計者によって維持されており、言語のあらゆる側面に関する究極の権威となります。開発者は、言語の正確な挙動を理解するためにこの仕様書を参照します。
EBNF (Extended Backus-Naur Form)
EBNFは、プログラミング言語の構文を記述するためのメタ言語です。Go言語の仕様書でも、構文規則を定義するためにEBNFが広く使用されています。EBNFの記法は以下のようになります。
=
:定義|
:選択(OR)[ ]
:オプション(0回または1回){ }
:繰り返し(0回以上)" "
:リテラル(終端記号)Identifier
:非終端記号(別の規則で定義される)
range
句
Go言語のfor
ステートメントでrange
句を使用すると、スライス、配列、文字列、マップ、チャネルなどのコレクションを反復処理できます。range
句は通常、2つの値を返します。最初の値はインデックスまたはキー、2番目の値は対応する要素の値です。これらの値は、range
句の左辺で変数に代入または宣言されます。
例:
for index, value := range slice {
// ...
}
select
ステートメントとRecvStmt
(Receive Statement)
select
ステートメントは、複数のチャネル操作を待機するために使用されます。select
は、準備ができたチャネル操作のいずれかを実行します。case
句には、チャネルからの受信操作(RecvStmt
)やチャネルへの送信操作(SendStmt
)が含まれます。
RecvStmt
は、チャネルから値を受信する操作です。受信した値は、左辺の変数に代入または宣言できます。
例:
select {
case value := <-ch:
// ...
case <-ch: // 値を破棄する場合
// ...
}
RecvStmt
は、受信した値と、操作が成功したかどうかを示すブール値の2つの値を返すこともできます。
select {
case value, ok := <-ch:
// ...
}
ExpressionList
とIdentifierList
ExpressionList
: 複数の式をカンマで区切ったリストを指します。Go言語では、複数の値を返す関数呼び出しの結果を複数の変数に代入する際などに使用されます。IdentifierList
: 複数の識別子(変数名)をカンマで区切ったリストを指します。Go言語では、複数の変数を宣言する際や、複数の値を返す関数の戻り値を受け取る際に使用されます。
技術的詳細
このコミットの核心は、Go言語の仕様書におけるRangeClause
とRecvStmt
のEBNF定義の修正です。
RangeClause
の変更
変更前:
RangeClause = Expression [ "," Expression ] ( "=" | ":=" ) "range" Expression .
この定義では、range
の左辺がExpression
またはExpression, Expression
であるとされていました。これは、単一の式や2つの式が左辺に来ることを示唆しており、Go言語がrange
の左辺で複数の変数宣言や代入を許可する実態と乖離がありました。
変更後:
RangeClause = ( ExpressionList "=" | IdentifierList ":=" ) "range" Expression .
この修正により、range
の左辺がExpressionList
(代入の場合)またはIdentifierList
(短い変数宣言の場合)であることが明確に示されました。
ExpressionList "="
: 既存の変数への代入(例:x, y = range ch
)IdentifierList ":="
: 新しい変数の短い宣言(例:x, y := range ch
)
この変更は、Go言語のrange
句が、インデックス/キーと値の両方を受け取るために複数の変数を使用できるという事実を正確に反映しています。
RecvStmt
の変更
変更前:
RecvStmt = [ Expression [ "," Expression ] ( "=" | ":=" ) ] RecvExpr .
この定義もRangeClause
と同様に、受信操作の左辺がExpression
またはExpression, Expression
であると示唆していました。Go言語では、チャネルからの受信結果を複数の変数(値と成功を示すブール値)で受け取ることが可能です。
変更後:
RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
この修正により、RecvStmt
の左辺もExpressionList
(代入の場合)またはIdentifierList
(短い変数宣言の場合)であることが明確に示されました。
ExpressionList "="
: 既存の変数への代入(例:value, ok = <-ch
)IdentifierList ":="
: 新しい変数の短い宣言(例:value, ok := <-ch
)
この変更は、チャネルからの受信操作が、受信した値と、受信が成功したかどうかを示すブール値の両方を返す場合に、複数の変数でそれらを受け取ることができるというGo言語のセマンティクスを正確に反映しています。
これらの修正は、Go言語の仕様書が言語の実際の挙動をより正確かつ明確に記述するための重要な改善です。
コアとなるコードの変更箇所
変更は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 January 11, 2013",
+ "Subtitle": "Version of January 18, 2013",
"Path": "/ref/spec"
}-->
@@ -4353,7 +4353,7 @@ to corresponding <i>iteration variables</i> and then executes the block.
</p>
<pre class="ebnf">
-RangeClause = Expression [ "," Expression ] ( "=" | ":=" ) "range" Expression .
+RangeClause = ( ExpressionList "=" | IdentifierList ":=" ) "range" Expression .
</pre>
<p>
@@ -4522,7 +4522,7 @@ cases all referring to communication operations.\n SelectStmt = "select" "{" { CommClause } "}" .\n CommClause = CommCase ":" { Statement ";" } .\n CommCase = "case" ( SendStmt | RecvStmt ) | "default" .\n-RecvStmt = [ Expression [ "," Expression ] ( "=" | ":=" ) ] RecvExpr .
+RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
RecvExpr = Expression .
</pre>
コアとなるコードの解説
このコミットでは、Go言語の仕様書(HTML形式)内のEBNF定義が修正されています。
-
Subtitle
の更新:- "Subtitle": "Version of January 11, 2013", + "Subtitle": "Version of January 18, 2013",
これは、仕様書のバージョン日付をコミット日に合わせて更新したものです。これは内容の変更ではなく、文書のメタデータ更新です。
-
RangeClause
のEBNF定義の変更:-RangeClause = Expression [ "," Expression ] ( "=" | ":=" ) "range" Expression . +RangeClause = ( ExpressionList "=" | IdentifierList ":=" ) "range" Expression .
この行が、
range
句の左辺の構文を修正する主要な変更です。- 変更前は、左辺が
Expression
またはExpression, Expression
(単一または2つの式)として定義されていました。 - 変更後は、左辺が
ExpressionList
(代入の場合)またはIdentifierList
(短い変数宣言の場合)であることが明確にされました。これにより、range
が複数の変数に値を割り当てたり、複数の変数を宣言したりできるというGoの機能が正確に反映されます。
- 変更前は、左辺が
-
RecvStmt
のEBNF定義の変更:-RecvStmt = [ Expression [ "," Expression ] ( "=" | ":=" ) ] RecvExpr . +RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
この行は、
select
ステートメント内の受信操作(RecvStmt
)の左辺の構文を修正する主要な変更です。- 変更前は、左辺が
Expression
またはExpression, Expression
として定義されていました。 - 変更後は、左辺が
ExpressionList
(代入の場合)またはIdentifierList
(短い変数宣言の場合)であることが明確にされました。これにより、チャネルからの受信が値と成功を示すブール値の両方を返す場合に、複数の変数でそれらを受け取ることができるというGoの機能が正確に反映されます。
- 変更前は、左辺が
これらの変更は、Go言語の仕様書が、言語の実際のセマンティクスと構文をより正確に、かつ曖昧さなく記述するための重要な修正です。
関連リンク
- GitHubコミット: https://github.com/golang/go/commit/d3679726b4639c27ca6b632374cdf4be1c74dbb6
- Go Issue #4653: https://github.com/golang/go/issues/4653
- Go CL 7135058: https://golang.org/cl/7135058
参考にした情報源リンク
- Go Language Specification: https://go.dev/ref/spec (現在の最新版)
- Extended Backus-Naur Form (EBNF)
- Go
for
statements: https://go.dev/ref/spec#For_statements - Go
select
statements: https://go.dev/ref/spec#Select_statements - Go Receive operator: https://go.dev/ref/spec#Receive_operator
- Go Short variable declarations: https://go.dev/ref/spec#Short_variable_declarations
- Go Assignments: https://go.dev/ref/spec#Assignments
- Go Expression lists: https://go.dev/ref/spec#Expression_lists
- Go Identifier lists: https://go.dev/ref/spec#Identifier_lists