[インデックス 1552] ファイルの概要
このコミットは、Go言語の仕様書(doc/go_spec.txt
)における重要な明確化と修正を目的としています。具体的には、スライスのインデックス範囲に関する規則と、インターフェース、スライス、マップ、チャネルといった複合型の比較に関する規則が詳細化されました。これにより、Go言語の動作の予測可能性と一貫性が向上し、開発者がこれらの型をより正確に理解し、利用できるようになります。また、関連するTODO項目が仕様書から削除され、これらの問題が解決されたことが示されています。
コミット
- clarified slice index bounds rules
- clarified comparisons of interfaces, slices, maps, channels
- removed respective TODO's
R=r
DELTA=76 (42 added, 16 deleted, 18 changed)
OCL=23132
CL=23479
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/18b05c1a8d9fc3c14a384df4bd78063de3b1d61a
元コミット内容
commit 18b05c1a8d9fc3c14a384df4bd78063de3b1d61a
Author: Robert Griesemer <gri@golang.org>
Date: Mon Jan 26 09:34:19 2009 -0800
- clarified slice index bounds rules
- clarified comparisons of interfaces, slices, maps, channels
- removed respective TODO's
R=r
DELTA=76 (42 added, 16 deleted, 18 changed)
OCL=23132
CL=23479
---
doc/go_spec.txt | 90 +++++++++++++++++++++++++++++++++++++--------------------\
1 file changed, 58 insertions(+), 32 deletions(-)
diff --git a/doc/go_spec.txt b/doc/go_spec.txt
index 6a64d5e4c6..9a10a5435d 100644
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -3,7 +3,7 @@ The Go Programming Language Specification (DRAFT)
Robert Griesemer, Rob Pike, Ken Thompson
-(January 22, 2009)
+(January 23, 2009)
----
@@ -40,22 +40,19 @@ Todo's:
w/ private fields: P.T{1, 2} illegal since same as P.T{a: 1, b: 2} for
a T struct { a b int }.
[ ] clarification on interface types, rules
-[ ] clarify slice rules
[ ] clarify tuples
[ ] need to talk about precise int/floats clearly
[ ] iant suggests to use abstract/precise int for len(), cap() - good idea
(issue: what happens in len() + const - what is the type?)
[ ] cleanup convert() vs T() vs x.(T) - convert() should go away?
-[ ] what are the permissible ranges for the indices in slices? The spec
- doesn't correspond to the implementation. The spec is wrong when it
- comes to the first index i: it should allow (at least) the range 0 <= i <= len(a).
- also: document different semantics for strings and arrays (strings cannot be grown).
[ ] fix "else" part of if statement
[ ] cleanup: 6g allows: interface { f F } where F is a function type.
fine, but then we should also allow: func f F {}, where F is a function type.
Open issues:
+[ ] do we need channel conversion (so we can go from uni-directional channel to
+ bi-directional channel)?
[ ] semantics of type decl: creating a new type or only a new type name?
[ ] at the moment: type T S; strips any methods of S. It probably shouldn't.
[ ] need for type switch? (or use type guard with ok in tuple assignment?)
@@ -79,6 +76,11 @@ Open issues:
Closed:
+[x] clarify slice rules
+[x] what are the permissible ranges for the indices in slices? The spec
+ doesn't correspond to the implementation. The spec is wrong when it
+ comes to the first index i: it should allow (at least) the range 0 <= i <= len(a).
+ also: document different semantics for strings and arrays (strings cannot be grown).
[x] reopening & and func issue: Seems inconsistent as both &func(){} and func(){} are
permitted. Suggestion: func literals are pointers. We need to use & for all other
functions. This would be in consistency with the declaration of function pointer
@@ -1409,6 +1411,20 @@ This allows the construction of mutually recursive types such as:\n Assignment compatibility: A value can be assigned to an interface variable\n if the static type of the value implements the interface or if the value is "nil".\n \n+Comparisons: A variable of interface type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n+\n+Two variables of interface type can be tested for equality with the\n+operators "==" and "!=" (§Comparison operators) if both variables have the\n+same static type. They are equal if both their dynamic types and values are\n+equal.\n+\n+TODO: Document situation where the dynamic types are equal but the values\n+don't support comparison.\n+\n \n Slice types\n ----\n@@ -1473,15 +1489,18 @@ operation:\n \ta[i : j]\n \n This creates the sub-slice consisting of the elements "a[i]" through "a[j - 1]"\n-(that is, excluding "a[j]"). "i" must be within array bounds, and "j" must satisfy\n-"i <= j <= cap(a)". The length of the new slice is "j - i". The capacity of\n+(that is, excluding "a[j]"). The values "i" and "j" must satisfy the condition\n+"0 <= i <= j <= cap(a)". The length of the new slice is "j - i". The capacity of\n the slice is "cap(a) - i"; thus if "i" is 0, the slice capacity does not change\n as a result of a slice operation. The type of a sub-slice is the same as the\n-type of the slice. Unlike the capacity, the length of a sub-slice\n-may be larger than the length of the original slice.\n+type of the slice. Unlike the capacity, the length of a sub-slice may be larger\n+than the length of the original slice.\n \n-TODO what are the proper restrictions on slices?\n-TODO describe equality checking against nil\n+Comparisons: A variable of slice type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n \n \n Map types\n@@ -1520,7 +1539,11 @@ of the map.\n Assignment compatibility: A map type is assignment compatible to a variable of\n map type only if both types are equal.\n \n-TODO: Comparison against nil\n+Comparisons: A variable of map type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n \n \n Channel types\n@@ -1555,11 +1578,20 @@ capacity is greater than zero, the channel is asynchronous and, provided the\n buffer is not full, sends can succeed without blocking. If the capacity is zero,\n the communication succeeds only when both a sender and receiver are ready.\n \n-Assignment compatibility:\n-TODO write this paragraph\n+Assignment compatibility: A value of type channel can be assigned to a variable\n+of type channel only if a) both types are equal (§Type equality), or b) both\n+have equal channel value types and the value is a bidirectional channel.\n+\n+Comparisons: A variable of channel type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n \n-TODO(gri): Do we need the channel conversion? It's enough to just keep\n-the assignment rule.\n+Two variables of channel type can be tested for equality with the\n+operators "==" and "!=" (§Comparison operators) if both variables have\n+the same ValueType. They are equal if both values were created by the same\n+"make" call (§Making slices, maps, and channels).\n \n \n Type equality\n@@ -2141,6 +2173,9 @@ The operand types in binary operations must be equal, with the following excepti\n \t (or an ideal number that can be safely converted into an unsigned int)\n \t (§Arithmetic operators).\n \n+\t- When comparing two operands of channel type, the channel value types\n+\t must be equal but the channel direction is ignored.\n+\n Unary operators have the highest precedence. They are evaluated from\n right to left. Note that "++" and "--" are outside the unary operator\n hierachy (they are statements) and they apply to the operand on the left.\n@@ -2264,7 +2299,7 @@ Comparison operators\n \n Comparison operators yield a boolean result. All comparison operators apply\n to strings and numeric types. The operators "==" and "!=" also apply to\n-boolean values, pointer, interface types, slice, map, and channel types\n+boolean values, pointer, interface, slice, map, and channel types\n (including the value "nil").\n \n \t== equal\n@@ -2276,19 +2311,13 @@ boolean values, pointer, interface types, slice, map, and channel types\n \n Strings are compared byte-wise (lexically).\n \n-Pointers are equal if they point to the same value.\n-\n-Interfaces are equal if both their dynamic types and values are equal.\n-For a value "v" of interface type, "v == nil" is true only if the predeclared\n-constant "nil" is assigned explicitly to "v" (§Assignments), or "v" has not\n-been modified since creation (§Program initialization and execution).\n-\n-TODO: Should we allow general comparison via interfaces? Problematic.\n+Booleans are equal if they are either both "true" or both "false".\n \n-Slices, maps, and channels are equal if they denote the same slice, map, or\n-channel respectively, or are "nil".\n+Pointers are equal if they point to the same value.\n \n-TODO: We need to be more precise here.\n+Interface, slice, map, and channel types can be compared for equality according\n+to the rules specified in the section on §Interface types, §Slice types, §Map types,\n+and §Channel types, respectively.\n \n \n Logical operators\n@@ -3360,6 +3389,3 @@ Program execution begins by initializing the main package and then\n invoking main.main().\n \n When main.main() returns, the program exits.\n-\n-TODO: is there a way to override the default for package main or the\n-default for the function name main.main?\n```
## 変更の背景
このコミットが行われた2009年1月は、Go言語がまだ活発に開発され、その仕様が固まりつつあった時期です。初期の言語設計では、特定の機能や型の振る舞いについて、実装は先行していても、その詳細な規則が仕様書に十分に明記されていない、あるいは曖昧な部分が存在していました。
特に、スライスのインデックス操作や、インターフェース、スライス、マップ、チャネルといったGo言語の重要な複合型の比較セマンティクスは、言語の健全性と開発者の期待に沿う挙動を保証するために、厳密な定義が必要でした。
このコミットの背景には、以下の具体的な課題があったと考えられます。
1. **スライスのインデックス範囲の曖昧さ**: スライスのスライス操作(`a[i:j]`)における`i`と`j`の有効な範囲が、当時の仕様書では実装と乖離していたり、十分に明確でなかった可能性があります。これにより、開発者が予期しないランタイムエラーに遭遇したり、コードの移植性が損なわれたりするリスクがありました。
2. **複合型の比較規則の不明瞭さ**: インターフェース、スライス、マップ、チャネルといった型は、Go言語の並行処理や抽象化において中心的な役割を果たします。これらの型が`nil`と比較されたり、他の同じ型の変数と比較されたりする際の厳密な規則が欠けていると、プログラムの論理が複雑になり、バグの温床となる可能性がありました。特に、Go言語ではこれらの型が参照型として扱われるため、値の比較と参照の比較の区別が重要です。
3. **仕様書のTODO項目の解消**: 開発中の仕様書には、将来的に明確化が必要な「TODO」項目が多数存在します。これらのTODOを解消し、仕様を完成させることは、言語の安定性と公式ドキュメントの信頼性を高める上で不可欠です。
これらの課題に対処するため、Robert Griesemer氏(Go言語の共同設計者の一人)によって、Go言語の仕様書にこれらの型の振る舞いに関する明確な規則が追加されました。
## 前提知識の解説
このコミットの変更内容を理解するためには、Go言語における以下の基本的な概念と、一般的なプログラミング言語におけるそれらの概念の扱いの違いを理解しておく必要があります。
### 1. Go言語の基本型と複合型
Go言語には、`int`, `bool`, `string`などの基本的な型(プリミティブ型)と、複数の要素を組み合わせた複合型があります。このコミットで焦点が当てられているのは、以下の複合型です。
* **スライス (Slice)**: Go言語における可変長シーケンス型です。配列の一部を参照するビューとして機能し、動的にサイズを変更できます。内部的には、ポインタ、長さ(`len`)、容量(`cap`)の3つの要素で構成されます。
* **インターフェース (Interface)**: 振る舞いを定義する型です。メソッドのシグネチャの集合を定義し、そのインターフェースのすべてのメソッドを実装する任意の型がそのインターフェースを満たします。Go言語のポリモーフィズムの主要なメカニズムです。インターフェース型の変数は、内部的に「型」と「値」のペアを保持します。
* **マップ (Map)**: キーと値のペアを格納するハッシュテーブルです。キーは一意であり、値に高速にアクセスできます。
* **チャネル (Channel)**: Go言語の並行処理におけるゴルーチン間の通信メカニズムです。チャネルを通じて値を送受信することで、ゴルーチン間で安全にデータを共有できます。
### 2. `nil` の概念
Go言語における `nil` は、他の言語の `null` に似ていますが、特定の型にのみ適用される「ゼロ値」です。ポインタ、インターフェース、スライス、マップ、チャネル、関数は `nil` になり得ます。`nil` は、これらの型がまだ有効な値や参照を保持していない状態を示します。
### 3. 型の比較 (Equality)
プログラミング言語において、2つの値が「等しい」と判断される基準は、型によって異なります。
* **プリミティブ型**: 通常、値が同じであれば等しいとされます(例: `5 == 5`)。
* **参照型**:
* **参照の等価性**: 2つの変数がメモリ上の同じオブジェクトを参照している場合に等しいとされます。
* **値の等価性**: 2つの変数が参照するオブジェクトの内容が同じである場合に等しいとされます。
Go言語では、スライス、マップ、チャネルは参照型として扱われますが、その比較セマンティクスは他の言語とは異なる場合があります。特に、Goではマップやスライスは直接 `==` 演算子で内容を比較することはできません(`nil`との比較を除く)。これは、これらの型の比較が複雑であり、開発者が意図しない挙動を避けるためです。
### 4. スライスのスライス操作 (`a[i:j]`)
Go言語のスライスは、既存の配列や他のスライスから新しいスライスを作成する「スライス操作」をサポートしています。`a[i:j]` は、元のスライス `a` のインデックス `i` から `j-1` までの要素を含む新しいスライスを作成します。この操作において、`i` と `j` の値がどのような範囲で有効であるかは、スライスの安全性と正確性を保証するために非常に重要です。
### 5. Go言語の仕様書 (Go Language Specification)
Go言語の仕様書は、Go言語の構文、セマンティクス、および標準ライブラリの振る舞いを定義する公式ドキュメントです。言語の設計者によって維持され、Goコンパイラやツールがこの仕様に準拠して動作することが期待されます。このコミットは、この仕様書自体を修正するものです。
## 技術的詳細
このコミットは、`doc/go_spec.txt` ファイルに対して行われたもので、Go言語の仕様における以下の重要な点を明確にしています。
### 1. スライスのインデックス範囲の明確化
スライスのスライス操作 `a[i : j]` におけるインデックス `i` と `j` の有効範囲がより厳密に定義されました。
**変更前**:
`"i" must be within array bounds, and "j" must satisfy "i <= j <= cap(a)"`
("i"は配列の境界内になければならず、"j"は"i <= j <= cap(a)"を満たさなければならない)
**変更後**:
`The values "i" and "j" must satisfy the condition "0 <= i <= j <= cap(a)"`
(値"i"と"j"は"0 <= i <= j <= cap(a)"の条件を満たさなければならない)
この変更により、スライスの開始インデックス `i` が `0` 以上であること、および `j` が `cap(a)`(スライスの容量)以下であることが明確にされました。これは、スライス操作が常に有効な範囲内で行われることを保証し、ランタイムパニック(インデックス範囲外エラー)を防ぐ上で非常に重要です。
### 2. インターフェースの比較規則の明確化
インターフェース型の変数の比較に関する詳細な規則が追加されました。
* **`nil` との比較**: インターフェース変数は `nil` と `==` または `!=` 演算子で比較できます。インターフェース変数が `nil` となるのは、明示的に `nil` が代入された場合、または作成されてから変更されていない場合のみです。これは、インターフェースが内部的に `(type, value)` のペアを持つため、`type` が `nil` でないが `value` が `nil` の場合(例: `var err error = (*MyError)(nil)`)には `nil` と等しくならないというGo特有の挙動を理解する上で重要です。
* **2つのインターフェース変数の比較**: 2つのインターフェース変数は、両方が同じ静的型を持つ場合に `==` または `!=` 演算子で比較できます。これらは、両方の動的型と値が等しい場合に等しいとされます。
* **TODOの追加**: 動的型が等しいが、値が比較をサポートしない状況(例: マップやスライスを含むインターフェース)に関するドキュメントの必要性がTODOとして追加されました。これは、Go言語の比較規則の複雑さを示唆しています。
### 3. スライスの比較規則の明確化
スライス型の変数の比較に関する詳細な規則が追加されました。
* **`nil` との比較**: スライス変数は `nil` と `==` または `!=` 演算子で比較できます。スライス変数が `nil` となるのは、明示的に `nil` が代入された場合、または作成されてから変更されていない場合のみです。Go言語では、スライスは `nil` スライス(長さと容量が0で、基底配列へのポインタが`nil`)と空スライス(長さと容量が0だが、基底配列へのポインタが`nil`でない)が区別されるため、この明確化は重要です。
### 4. マップの比較規則の明確化
マップ型の変数の比較に関する詳細な規則が追加されました。
* **`nil` との比較**: マップ変数は `nil` と `==` または `!=` 演算子で比較できます。マップ変数が `nil` となるのは、明示的に `nil` が代入された場合、または作成されてから変更されていない場合のみです。Go言語では、マップは `nil` マップ(初期化されていないマップ)と空マップ(`make(map[K]V)`で作成されたが要素がないマップ)が区別されるため、この明確化は重要です。Goではマップ同士を直接 `==` で比較することはできません。
### 5. チャネルの比較規則の明確化
チャネル型の変数の比較に関する詳細な規則が追加されました。
* **代入互換性**: チャネル型の値は、a) 両方の型が等しい場合、または b) 両方が等しいチャネル値型を持ち、かつ値が双方向チャネルである場合に、チャネル型の変数に代入できます。
* **`nil` との比較**: チャネル変数は `nil` と `==` または `!=` 演算子で比較できます。チャネル変数が `nil` となるのは、明示的に `nil` が代入された場合、または作成されてから変更されていない場合のみです。
* **2つのチャネル変数の比較**: 2つのチャネル変数は、両方が同じ `ValueType` を持つ場合に `==` または `!=` 演算子で比較できます。これらは、両方の値が同じ `make` 呼び出しによって作成された場合に等しいとされます。これは、チャネルの等価性が参照の等価性に基づいていることを意味します。
* **比較演算子におけるチャネルの扱い**: 二項演算におけるオペランドの型が等しい必要があるという規則に、チャネル型の場合の例外が追加されました。チャネル型を比較する場合、チャネル値型は等しい必要がありますが、チャネルの方向(単方向か双方向か)は無視されます。
### 6. 比較演算子セクションの更新
一般的な「比較演算子」のセクションが更新され、インターフェース、スライス、マップ、チャネルの比較規則については、それぞれの型のセクションを参照するように変更されました。これにより、情報が重複せず、より整理された形で提供されるようになりました。また、ブール値とポインタの比較に関する記述も簡潔化されました。
これらの変更は、Go言語の仕様をより正確で、網羅的で、理解しやすいものにするための重要なステップでした。特に、複合型の比較セマンティクスは、Goプログラムの正確性と予測可能性に直接影響するため、これらの明確化は開発者にとって非常に価値のあるものです。
## コアとなるコードの変更箇所
```diff
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -3,7 +3,7 @@ The Go Programming Language Specification (DRAFT)
Robert Griesemer, Rob Pike, Ken Thompson
-(January 22, 2009)
+(January 23, 2009)
----
@@ -40,22 +40,19 @@ Todo's:
w/ private fields: P.T{1, 2} illegal since same as P.T{a: 1, b: 2} for
a T struct { a b int }.
[ ] clarification on interface types, rules
-[ ] clarify slice rules
[ ] clarify tuples
[ ] need to talk about precise int/floats clearly
[ ] iant suggests to use abstract/precise int for len(), cap() - good idea
(issue: what happens in len() + const - what is the type?)
[ ] cleanup convert() vs T() vs x.(T) - convert() should go away?
-[ ] what are the permissible ranges for the indices in slices? The spec
- doesn't correspond to the implementation. The spec is wrong when it
- comes to the first index i: it should allow (at least) the range 0 <= i <= len(a).\n also: document different semantics for strings and arrays (strings cannot be grown).
[ ] fix "else" part of if statement
[ ] cleanup: 6g allows: interface { f F } where F is a function type.
fine, but then we should also allow: func f F {}, where F is a function type.
Open issues:
+[ ] do we need channel conversion (so we can go from uni-directional channel to
+ bi-directional channel)?
[ ] semantics of type decl: creating a new type or only a new type name?
[ ] at the moment: type T S; strips any methods of S. It probably shouldn't.
[ ] need for type switch? (or use type guard with ok in tuple assignment?)
@@ -79,6 +76,11 @@ Open issues:
Closed:
+[x] clarify slice rules
+[x] what are the permissible ranges for the indices in slices? The spec
+ doesn't correspond to the implementation. The spec is wrong when it
+ comes to the first index i: it should allow (at least) the range 0 <= i <= len(a).\n also: document different semantics for strings and arrays (strings cannot be grown).
[x] reopening & and func issue: Seems inconsistent as both &func(){} and func(){} are
permitted. Suggestion: func literals are pointers. We need to use & for all other
functions. This would be in consistency with the declaration of function pointer
@@ -1409,6 +1411,20 @@ This allows the construction of mutually recursive types such as:\n Assignment compatibility: A value can be assigned to an interface variable\n if the static type of the value implements the interface or if the value is "nil".\n \n+Comparisons: A variable of interface type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n+\n+Two variables of interface type can be tested for equality with the\n+operators "==" and "!=" (§Comparison operators) if both variables have the\n+same static type. They are equal if both their dynamic types and values are\n+equal.\n+\n+TODO: Document situation where the dynamic types are equal but the values\n+don't support comparison.\n+\n \n Slice types\n ----\n@@ -1473,15 +1489,18 @@ operation:\n \ta[i : j]\n \n This creates the sub-slice consisting of the elements "a[i]" through "a[j - 1]"\n-(that is, excluding "a[j]"). "i" must be within array bounds, and "j" must satisfy\n-"i <= j <= cap(a)". The length of the new slice is "j - i". The capacity of\n+(that is, excluding "a[j]"). The values "i" and "j" must satisfy the condition\n+"0 <= i <= j <= cap(a)". The length of the new slice is "j - i". The capacity of\n the slice is "cap(a) - i"; thus if "i" is 0, the slice capacity does not change\n as a result of a slice operation. The type of a sub-slice is the same as the\n-type of the slice. Unlike the capacity, the length of a sub-slice\n-may be larger than the length of the original slice.\n+type of the slice. Unlike the capacity, the length of a sub-slice may be larger\n+than the length of the original slice.\n \n-TODO what are the proper restrictions on slices?\n-TODO describe equality checking against nil\n+Comparisons: A variable of slice type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n \n \n Map types\n@@ -1520,7 +1539,11 @@ of the map.\n Assignment compatibility: A map type is assignment compatible to a variable of\n map type only if both types are equal.\n \n-TODO: Comparison against nil\n+Comparisons: A variable of map type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n \n \n Channel types\n@@ -1555,11 +1578,20 @@ capacity is greater than zero, the channel is asynchronous and, provided the\n buffer is not full, sends can succeed without blocking. If the capacity is zero,\n the communication succeeds only when both a sender and receiver are ready.\n \n-Assignment compatibility:\n-TODO write this paragraph\n+Assignment compatibility: A value of type channel can be assigned to a variable\n+of type channel only if a) both types are equal (§Type equality), or b) both\n+have equal channel value types and the value is a bidirectional channel.\n+\n+Comparisons: A variable of channel type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n \n-TODO(gri): Do we need the channel conversion? It's enough to just keep\n-the assignment rule.\n+Two variables of channel type can be tested for equality with the\n+operators "==" and "!=" (§Comparison operators) if both variables have\n+the same ValueType. They are equal if both values were created by the same\n+"make" call (§Making slices, maps, and channels).\n \n \n Type equality\n@@ -2141,6 +2173,9 @@ The operand types in binary operations must be equal, with the following excepti\n \t (or an ideal number that can be safely converted into an unsigned int)\n \t (§Arithmetic operators).\n \n+\t- When comparing two operands of channel type, the channel value types\n+\t must be equal but the channel direction is ignored.\n+\n Unary operators have the highest precedence. They are evaluated from\n right to left. Note that "++" and "--" are outside the unary operator\n hierachy (they are statements) and they apply to the operand on the left.\n@@ -2264,7 +2299,7 @@ Comparison operators\n \n Comparison operators yield a boolean result. All comparison operators apply\n to strings and numeric types. The operators "==" and "!=" also apply to\n-boolean values, pointer, interface types, slice, map, and channel types\n+boolean values, pointer, interface, slice, map, and channel types\n (including the value "nil").\n \n \t== equal\n@@ -2276,19 +2311,13 @@ boolean values, pointer, interface types, slice, map, and channel types\n \n Strings are compared byte-wise (lexically).\n \n-Pointers are equal if they point to the same value.\n-\n-Interfaces are equal if both their dynamic types and values are equal.\n-For a value "v" of interface type, "v == nil" is true only if the predeclared\n-constant "nil" is assigned explicitly to "v" (§Assignments), or "v" has not\n-been modified since creation (§Program initialization and execution).\n-\n-TODO: Should we allow general comparison via interfaces? Problematic.\n+Booleans are equal if they are either both "true" or both "false".\n \n-Slices, maps, and channels are equal if they denote the same slice, map, or\n-channel respectively, or are "nil".\n+Pointers are equal if they point to the same value.\n \n-TODO: We need to be more precise here.\n+Interface, slice, map, and channel types can be compared for equality according\n+to the rules specified in the section on §Interface types, §Slice types, §Map types,\n+and §Channel types, respectively.\n \n \n Logical operators\n@@ -3360,6 +3389,3 @@ Program execution begins by initializing the main package and then\n invoking main.main().\n \n When main.main() returns, the program exits.\n-\n-TODO: is there a way to override the default for package main or the\n-default for the function name main.main?\n```
## コアとなるコードの解説
このコミットの主要な変更は、Go言語の仕様書 `doc/go_spec.txt` 内のテキスト修正です。以下に、変更された主要なセクションとその意味を解説します。
1. **日付の更新**:
```diff
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -3,7 +3,7 @@ The Go Programming Language Specification (DRAFT)
Robert Griesemer, Rob Pike, Ken Thompson
-(January 22, 2009)
+(January 23, 2009)
```
仕様書の日付が「January 22, 2009」から「January 23, 2009」に更新されました。これは、このコミットが2009年1月23日に行われたことを示しています。
2. **TODO項目の削除とクローズ**:
```diff
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -40,22 +40,19 @@ Todo's:
w/ private fields: P.T{1, 2} illegal since same as P.T{a: 1, b: 2} for
a T struct { a b int }.
[ ] clarification on interface types, rules
-[ ] clarify slice rules
[ ] clarify tuples
[ ] need to talk about precise int/floats clearly
[ ] iant suggests to use abstract/precise int for len(), cap() - good idea
(issue: what happens in len() + const - what is the type?)
[ ] cleanup convert() vs T() vs x.(T) - convert() should go away?
-[ ] what are the permissible ranges for the indices in slices? The spec
- doesn't correspond to the implementation. The spec is wrong when it
- comes to the first index i: it should allow (at least) the range 0 <= i <= len(a).\n also: document different semantics for strings and arrays (strings cannot be grown).
[ ] fix "else" part of if statement
[ ] cleanup: 6g allows: interface { f F } where F is a function type.
fine, but then we should also allow: func f F {}, where F is a function type.
Open issues:
+[ ] do we need channel conversion (so we can go from uni-directional channel to
+ bi-directional channel)?
[ ] semantics of type decl: creating a new type or only a new type name?
[ ] at the moment: type T S; strips any methods of S. It probably shouldn't.
[ ] need for type switch? (or use type guard with ok in tuple assignment?)
@@ -79,6 +76,11 @@ Open issues:
Closed:
+[x] clarify slice rules
+[x] what are the permissible ranges for the indices in slices? The spec
+ doesn't correspond to the implementation. The spec is wrong when it
+ comes to the first index i: it should allow (at least) the range 0 <= i <= len(a).\n also: document different semantics for strings and arrays (strings cannot be grown).
[x] reopening & and func issue: Seems inconsistent as both &func(){} and func(){} are
permitted. Suggestion: func literals are pointers. We need to use & for all other
functions. This would be in consistency with the declaration of function pointer
```
「Todo's」セクションから、スライスの規則とインデックス範囲に関するTODO項目が削除されました。代わりに、「Closed」セクションにこれらの項目が `[x]` 付きで追加され、解決済みであることが示されています。これは、このコミットによってこれらの仕様の曖昧さが解消されたことを意味します。
3. **インターフェースの比較規則の追加**:
```diff
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -1409,6 +1411,20 @@ This allows the construction of mutually recursive types such as:\n Assignment compatibility: A value can be assigned to an interface variable\n if the static type of the value implements the interface or if the value is "nil".\n \n+Comparisons: A variable of interface type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n+\n+Two variables of interface type can be tested for equality with the\n+operators "==" and "!=" (§Comparison operators) if both variables have the\n+same static type. They are equal if both their dynamic types and values are\n+equal.\n+\n+TODO: Document situation where the dynamic types are equal but the values\n+don't support comparison.\n+\n \n Slice types
----
```
「Interface types」セクションに「Comparisons」という新しいサブセクションが追加されました。ここでは、インターフェース変数が `nil` と比較される条件、および2つのインターフェース変数が比較される条件が詳細に記述されています。特に、動的型と値の両方が等しい場合にインターフェースが等しいと見なされる点が強調されています。また、値が比較をサポートしない場合のTODOが追加されています。
4. **スライスのインデックス範囲の明確化**:
```diff
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -1473,15 +1489,18 @@ operation:\n \ta[i : j]\n \n This creates the sub-slice consisting of the elements "a[i]" through "a[j - 1]"\n-(that is, excluding "a[j]"). "i" must be within array bounds, and "j" must satisfy\n-"i <= j <= cap(a)". The length of the new slice is "j - i". The capacity of\n+(that is, excluding "a[j]"). The values "i" and "j" must satisfy the condition\n+"0 <= i <= j <= cap(a)". The length of the new slice is "j - i". The capacity of\n the slice is "cap(a) - i"; thus if "i" is 0, the slice capacity does not change\n as a result of a slice operation. The type of a sub-slice is the same as the\n-type of the slice. Unlike the capacity, the length of a sub-slice\n-may be larger than the length of the original slice.\n+type of the slice. Unlike the capacity, the length of a sub-slice may be larger\n+than the length of the original slice.\n ```
スライスのスライス操作 `a[i : j]` の説明において、`i` と `j` の有効な範囲が「`0 <= i <= j <= cap(a)`」と明確に定義されました。これにより、スライス操作の境界条件が厳密になり、より予測可能な挙動が保証されます。
5. **スライス、マップ、チャネルの `nil` 比較規則の追加**:
```diff
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -1473,15 +1489,18 @@ operation:\n \ta[i : j]\n \n This creates the sub-slice consisting of the elements "a[i]" through "a[j - 1]"\n-(that is, excluding "a[j]"). "i" must be within array bounds, and "j" must satisfy\n-"i <= j <= cap(a)". The length of the new slice is "j - i". The capacity of\n+(that is, excluding "a[j]"). The values "i" and "j" must satisfy the condition\n+"0 <= i <= j <= cap(a)". The length of the new slice is "j - i". The capacity of\n the slice is "cap(a) - i"; thus if "i" is 0, the slice capacity does not change\n as a result of a slice operation. The type of a sub-slice is the same as the\n-type of the slice. Unlike the capacity, the length of a sub-slice\n-may be larger than the length of the original slice.\n+type of the slice. Unlike the capacity, the length of a sub-slice may be larger\n+than the length of the original slice.\n \n-TODO what are the proper restrictions on slices?\n-TODO describe equality checking against nil\n+Comparisons: A variable of slice type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n \n \n Map types\n@@ -1520,7 +1539,11 @@ of the map.\n Assignment compatibility: A map type is assignment compatible to a variable of\n map type only if both types are equal.\n \n-TODO: Comparison against nil\n+Comparisons: A variable of map type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n \n \n Channel types\n@@ -1555,11 +1578,20 @@ capacity is greater than zero, the channel is asynchronous and, provided the\n buffer is not full, sends can succeed without blocking. If the capacity is zero,\n the communication succeeds only when both a sender and receiver are ready.\n \n-Assignment compatibility:\n-TODO write this paragraph\n+Assignment compatibility: A value of type channel can be assigned to a variable\n+of type channel only if a) both types are equal (§Type equality), or b) both\n+have equal channel value types and the value is a bidirectional channel.\n+\n+Comparisons: A variable of channel type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n \n-TODO(gri): Do we need the channel conversion? It's enough to just keep\n-the assignment rule.\n+Two variables of channel type can be tested for equality with the\n+operators "==" and "!=" (§Comparison operators) if both variables have\n+the same ValueType. They are equal if both values were created by the same\n+"make" call (§Making slices, maps, and channels).\n ```
スライス、マップ、チャネルの各セクションに、それぞれの型が `nil` と比較される際の規則が追加されました。これにより、これらの参照型が `nil` となる条件が明確化され、開発者が `nil` の扱いを誤るリスクが軽減されます。
6. **チャネルの代入互換性と比較規則の追加**:
```diff
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -1555,11 +1578,20 @@ capacity is greater than zero, the channel is asynchronous and, provided the\n buffer is not full, sends can succeed without blocking. If the capacity is zero,\n the communication succeeds only when both a sender and receiver are ready.\n \n-Assignment compatibility:\n-TODO write this paragraph\n+Assignment compatibility: A value of type channel can be assigned to a variable\n+of type channel only if a) both types are equal (§Type equality), or b) both\n+have equal channel value types and the value is a bidirectional channel.\n+\n+Comparisons: A variable of channel type can be compared against "nil" with the\n+operators "==" and "!=" (§Comparison operators). The variable is\n+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or\n+if the variable has not been modified since creation (§Program initialization\n+and execution).\n \n-TODO(gri): Do we need the channel conversion? It's enough to just keep\n-the assignment rule.\n+Two variables of channel type can be tested for equality with the\n+operators "==" and "!=" (§Comparison operators) if both variables have\n+the same ValueType. They are equal if both values were created by the same\n+"make" call (§Making slices, maps, and channels).\n ```
チャネルの代入互換性に関する記述が追加され、チャネルの比較規則も詳細化されました。特に、2つのチャネルが等しいと見なされるのは、同じ `make` 呼び出しによって作成された場合であるという点が重要です。
7. **比較演算子セクションの更新**:
```diff
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -2141,6 +2173,9 @@ The operand types in binary operations must be equal, with the following excepti\n \t (or an ideal number that can be safely converted into an unsigned int)\n \t (§Arithmetic operators).\n \n+\t- When comparing two operands of channel type, the channel value types\n+\t must be equal but the channel direction is ignored.\n+\n Unary operators have the highest precedence. They are evaluated from\n right to left. Note that "++" and "--" are outside the unary operator\n hierachy (they are statements) and they apply to the operand on the left.\n@@ -2264,7 +2299,7 @@ Comparison operators\n \n Comparison operators yield a boolean result. All comparison operators apply\n to strings and numeric types. The operators "==" and "!=" also apply to\n-boolean values, pointer, interface types, slice, map, and channel types\n+boolean values, pointer, interface, slice, map, and channel types\n (including the value "nil").\n \n \t== equal\n@@ -2276,19 +2311,13 @@ boolean values, pointer, interface types, slice, map, and channel types\n \n Strings are compared byte-wise (lexically).\n \n-Pointers are equal if they point to the same value.\n-\n-Interfaces are equal if both their dynamic types and values are equal.\n-For a value "v" of interface type, "v == nil" is true only if the predeclared\n-constant "nil" is assigned explicitly to "v" (§Assignments), or "v" has not\n-been modified since creation (§Program initialization and execution).\n-\n-TODO: Should we allow general comparison via interfaces? Problematic.\n+Booleans are equal if they are either both "true" or both "false".\n \n-Slices, maps, and channels are equal if they denote the same slice, map, or\n-channel respectively, or are "nil".\n+Pointers are equal if they point to the same value.\n \n-TODO: We need to be more precise here.\n+Interface, slice, map, and channel types can be compared for equality according\n+to the rules specified in the section on §Interface types, §Slice types, §Map types,\n+and §Channel types, respectively.\n ```
「Comparison operators」セクションが大幅に改訂されました。以前はインターフェース、スライス、マップ、チャネルの比較に関する記述がこのセクションに直接含まれていましたが、変更後はそれぞれの型のセクション(`§Interface types`, `§Slice types`, `§Map types`, `§Channel types`)を参照するように簡潔化されました。これにより、仕様書全体の構造が改善され、情報の重複が避けられています。また、チャネルの比較において、チャネル値型が等しければチャネルの方向は無視されるという新しい規則が追加されました。
これらの変更は、Go言語の初期段階における仕様の成熟度を高め、言語の振る舞いをより明確かつ厳密に定義することを目的としていました。
## 関連リンク
* [The Go Programming Language Specification](https://go.dev/ref/spec) - Go言語の公式仕様書。このコミットで変更されたドキュメントの最新版。
* [Go Blog: The Laws of Reflection](https://go.dev/blog/laws-of-reflection) - Goのインターフェースとリフレクションに関する詳細な解説。インターフェースの内部構造(型と値のペア)を理解するのに役立ちます。
* [Go Slices: usage and internals](https://go.dev/blog/slices) - Goのスライスの動作と内部構造に関する公式ブログ記事。スライスのインデックス操作と容量の概念を理解するのに役立ちます。
* [Go Concurrency Patterns: Pipelines and Cancellation](https://go.dev/blog/pipelines) - Goのチャネルと並行処理パターンに関する公式ブログ記事。チャネルの基本的な使い方と重要性を理解するのに役立ちます。
## 参考にした情報源リンク
* Go言語の公式ドキュメントおよびブログ記事
* Gitのコミット履歴と差分表示
* Go言語の仕様に関する一般的な知識