[インデックス 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
forstatements: https://go.dev/ref/spec#For_statements - Go
selectstatements: 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